<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="generator" content="VNote">

    <title>12_客户端-服务端ORM</title>
    <link rel="icon" href="https://github.com/tamlok/vnote/raw/master/src/resources/icons/vnote.ico">

    <style type="text/css">
    /* STYLE_GLOBAL_PLACE_HOLDER */
    </style>

    <style type="text/css">
    *,
*::before,
*::after {
  box-sizing: border-box;
}

.container-fluid {
    width: 100%;
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
}

.col, .col-1, .col-10, .col-11, .col-12, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-auto, .col-lg, .col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-auto, .col-md, .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-auto, .col-sm, .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-auto, .col-xl, .col-xl-1, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-auto {
    position: relative;
    width: 100%;
    min-height: 1px;
    padding-right: 15px;
    padding-left: 15px;
}

.col-12 {
    -webkit-box-flex: 0;
    -ms-flex: 0 0 100%;
    flex: 0 0 100%;
    max-width: 100%;
}

@media (min-width: 768px) {
    .col-md-3 {
        -webkit-box-flex: 0;
        -ms-flex: 0 0 25%;
        flex: 0 0 25%;
        max-width: 25%;
    }
}

@media (min-width: 768px) {
    .col-md-9 {
        -webkit-box-flex: 0;
        -ms-flex: 0 0 75%;
        flex: 0 0 75%;
        max-width: 75%;
    }
}

@media (min-width: 1200px) {
    .col-xl-2 {
        -webkit-box-flex: 0;
        -ms-flex: 0 0 16.666667%;
        flex: 0 0 16.666667%;
        max-width: 16.666667%;
    }
}

@media (min-width: 1200px) {
    .col-xl-10 {
        -webkit-box-flex: 0;
        -ms-flex: 0 0 83.333333%;
        flex: 0 0 83.333333%;
        max-width: 83.333333%;
    }
}

@media (min-width: 768px) {
    .pt-md-3, .py-md-3 {
        padding-top: 1rem!important;
    }
}

@media (min-width: 768px) {
    .pb-md-3, .py-md-3 {
        padding-bottom: 1rem!important;
    }
}

@media (min-width: 768px) {
    .pl-md-5, .px-md-5 {
        padding-left: 3rem!important;
    }
}

.d-none {
    display: none!important;
}

@media (min-width: 1200px) {
    .d-xl-block {
        display: block!important;
    }
}

@media (min-width: 768px) {
    .d-md-block {
        display: block!important;
    }
}

.bd-content {
    -webkit-box-ordinal-group: 1;
    -ms-flex-order: 0;
    order: 0;
}

.bd-toc {
    position: -webkit-sticky;
    position: sticky;
    top: 4rem;
    height: calc(100vh - 10rem);
    overflow-y: auto;
}

.bd-toc {
    -webkit-box-ordinal-group: 2;
    -ms-flex-order: 1;
    order: 1;
    padding-top: 1.5rem;
    padding-bottom: 1.5rem;
    font-size: .875rem;
}

.section-nav {
    padding-left: 0;
}

.section-nav ul {
    font-size: .875rem;
    list-style-type: none;
}

.section-nav li {
    font-size: .875rem;
}

.section-nav a {
    color: inherit !important;
}

.row {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-wrap: wrap;
    flex-wrap: wrap;
    margin-right: -15px;
    margin-left: -15px;
}

@media (min-width: 1200px) {
    .flex-xl-nowrap {
        flex-wrap: nowrap !important;
    }
}

#floating-button {
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 50%;
    background: #00897B;
    position: fixed;
    top: .5rem;
    right: .5rem;
    cursor: pointer;
    box-shadow: 0px 2px 5px #666;
}

#floating-button .more {
    color: #F5F5F5;
    position: absolute;
    top: 0;
    display: block;
    bottom: 0;
    left: 0;
    right: 0;
    text-align: center;
    padding: 0;
    margin: 0;
    line-height: 2.5rem;
    font-size: 2rem;
    font-family: 'monospace';
    font-weight: 300;
}

.hide-none {
    display: none !important;
}

.col-expand {
    -webkit-box-flex: 0;
    -ms-flex: 0 0 100% !important;
    flex: 0 0 100% !important;
    max-width: 100% !important;
    padding-right: 3rem !important;
}

.outline-bold {
    font-weight: bolder !important;
}

@media print {
    #floating-button {
        display: none !important;
    }
}

    @keyframes flash { 
  0% { color: rgb(128, 203, 196); }
  10% { color: rgb(0, 137, 123); }
  40% { color: rgb(0, 137, 123); }
  50% { color: rgb(128, 203, 196); }
  60% { color: rgb(0, 137, 123); }
  90% { color: rgb(0, 137, 123); }
}
.highlighted-anchor { animation: flash 1s; }
div.mark-rect { background: transparent; border: 5px solid rgb(87, 104, 196); border-radius: 2px; position: absolute; }
#vnote-footer { width: 100%; text-align: center; opacity: 0.2; margin-top: 3rem; }
#vnote-footer p { font-size: 0.8rem; }
#vnote-footer a { color: inherit !important; }
x-eqs { display: flex; flex-direction: row; align-content: space-between; align-items: center; }
x-eqs > x-eqn { width: 100%; margin-left: 3rem; }
x-eqs > span { text-align: right; }
.view-image, .view-svg { transition: 0.3s; }
.modal-box { display: none; position: fixed; z-index: 1000; padding-top: 50px; left: 0px; top: 0px; width: 100%; height: 100%; overflow: hidden; background-color: rgba(68, 68, 68, 0.952941); }
.modal-content { margin: auto; display: block; width: auto; height: auto; cursor: move; }
.modal-content { animation-name: zoom; animation-duration: 0.6s; }
@-webkit-keyframes zoom { 
  0% { transform: scale(0); }
  100% { transform: scale(1); }
}
@keyframes zoom { 
  0% { transform: scale(0); }
  100% { transform: scale(1); }
}
span.modal-close { position: absolute; z-index: 1000; top: 15px; right: 35px; color: rgb(218, 218, 218); font-size: 40px; font-weight: bold; transition: 0.3s; }
span.modal-close:hover, span.modal-close:focus { color: rgb(238, 238, 238); text-decoration: none; cursor: pointer; }
@media print {
  pre, pre code, td.hljs-ln-code { white-space: pre-wrap !important; word-break: break-all !important; }
  code, a { word-break: break-all !important; }
  div.flowchart-diagram, div.mermaid-diagram, div.plantuml-diagram { overflow: hidden !important; }
  img { max-width: 100% !important; height: auto !important; }
  #vnote-footer { display: none !important; }
}
.alert { position: relative; padding: 0.75rem 1.25rem; margin-bottom: 1rem; border: 1px solid transparent; border-radius: 0.25rem; }
.alert-primary { color: rgb(0, 64, 133); background-color: rgb(204, 229, 255); border-color: rgb(184, 218, 255); }
.alert-secondary { color: rgb(56, 61, 65); background-color: rgb(226, 227, 229); border-color: rgb(214, 216, 219); }
.alert-success { color: rgb(21, 87, 36); background-color: rgb(212, 237, 218); border-color: rgb(195, 230, 203); }
.alert-info { color: rgb(12, 84, 96); background-color: rgb(209, 236, 241); border-color: rgb(190, 229, 235); }
.alert-warning { color: rgb(133, 100, 4); background-color: rgb(255, 243, 205); border-color: rgb(255, 238, 186); }
.alert-danger { color: rgb(114, 28, 36); background-color: rgb(248, 215, 218); border-color: rgb(245, 198, 203); }
.alert-light { color: rgb(129, 129, 130); background-color: rgb(254, 254, 254); border-color: rgb(253, 253, 254); }
.alert-dark { color: rgb(27, 30, 33); background-color: rgb(214, 216, 217); border-color: rgb(198, 200, 202); }
.vnote-anchor { font-weight: 400; color: rgba(0, 123, 255, 0.498039); transition: color 0.16s linear; padding-left: 0.375em; -webkit-font-smoothing: antialiased; text-decoration: none; opacity: 0; }
.vnote-anchor:hover { color: rgb(0, 123, 255); text-decoration: none; opacity: 1; }
.vnote-anchor::after { content: attr(data-anchor-icon); }
.vnote-btn { position: relative; display: inline-block; padding: 6px 12px; font-size: 13px; font-weight: 700; line-height: 20px; white-space: nowrap; vertical-align: middle; cursor: pointer; border: none; user-select: none; -webkit-appearance: none; }
.vnote-copy-clipboard-btn { transition: opacity 0.3s ease-in-out; opacity: 0; padding: 2px 6px; position: absolute; top: 5px; right: 5px; }
pre:hover .vnote-copy-clipboard-btn { opacity: 1; }
pre.vnote-snippet { position: relative; }
body { margin: 0px auto; font-family: "Segoe UI", Helvetica, sans-serif, Tahoma, Arial, Geneva, Georgia, Palatino, "Times New Roman", "Hiragino Sans GB", 冬青黑体, "Microsoft YaHei", 微软雅黑, "Microsoft YaHei UI", "WenQuanYi Micro Hei", 文泉驿雅黑, Dengxian, 等线体, STXihei, 华文细黑, "Liberation Sans", "Droid Sans", NSimSun, 新宋体, SimSun, 宋体; color: rgb(34, 34, 34); line-height: 1.5; padding: 15px; background: rgb(238, 238, 238); font-size: 16px; }
h1, h2, h3, h4, h5, h6 { color: rgb(34, 34, 34); font-weight: bold; margin-top: 20px; margin-bottom: 10px; padding: 0px; }
p { padding: 0px; margin-top: 16px; margin-bottom: 16px; }
h1 { font-size: 26px; }
h2 { font-size: 24px; }
h3 { font-size: 22px; }
h4 { font-size: 20px; }
h5 { font-size: 19px; }
h6 { font-size: 18px; }
a { color: rgb(0, 153, 255); margin: 0px; padding: 0px; vertical-align: baseline; text-decoration: none; word-break: break-word; }
a:hover { text-decoration: underline; color: rgb(255, 102, 0); }
a:visited { color: purple; }
ul, ol { padding: 0px 0px 0px 24px; }
li { line-height: 24px; }
li ul, li ol { margin-left: 16px; }
p, ul, ol { font-size: 16px; line-height: 24px; }
pre { display: block; overflow-y: hidden; overflow-x: auto; tab-size: 4; }
code { font-family: Consolas, Monaco, monospace, Courier; color: rgb(142, 36, 170); word-break: break-word; }
pre code { display: block; overflow-x: auto; padding: 0.5em; color: rgb(34, 34, 34); background-color: rgb(224, 224, 224); border-left: 0.5em solid rgb(0, 137, 123); line-height: 1.5; font-family: Consolas, Monaco, monospace, Courier; white-space: pre; tab-size: 4; }
pre code.markdown-metadata { border-left: 0.5em solid rgb(128, 203, 196); }
aside { display: block; float: right; width: 390px; }
blockquote { color: rgb(102, 102, 102); border-left: 0.5em solid rgb(122, 122, 122); padding: 0px 1em; margin-left: 0px; }
blockquote p { color: rgb(102, 102, 102); }
hr { display: block; text-align: left; margin: 1em 0px; border: none; height: 2px; background: rgb(153, 153, 153); }
table { padding: 0px; margin: 1rem 0.5rem; border-collapse: collapse; }
table tr { border-top: 2px solid rgb(204, 204, 204); background-color: white; margin: 0px; padding: 0px; }
table tr:nth-child(2n) { background-color: rgb(248, 248, 248); }
table tr th { font-weight: bold; border: 2px solid rgb(204, 204, 204); margin: 0px; padding: 6px 13px; }
table tr td { border: 2px solid rgb(204, 204, 204); margin: 0px; padding: 6px 13px; }
table tr th :first-child, table tr td :first-child { margin-top: 0px; }
table tr th :last-child, table tr td :last-child { margin-bottom: 0px; }
div.mermaid-diagram { margin: 16px 0px; overflow-y: hidden; }
div.flowchart-diagram { padding: 0px 5px; margin: 16px 0px; width: fit-content; overflow: hidden; }
div.wavedrom-diagram { padding: 0px 5px; margin: 16px 0px; width: fit-content; overflow: hidden; }
div.plantuml-diagram { padding: 5px 5px 0px; margin: 16px 0px; width: fit-content; overflow: hidden; }
.img-package { text-align: center; }
img.img-center { display: block; margin-left: auto; margin-right: auto; }
span.img-caption { min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid rgb(192, 192, 192); color: rgb(108, 108, 108); text-align: center; line-height: 1.5; }
.emoji_zero, .emoji_one, .emoji_two, .emoji_three, .emoji_four, .emoji_five, .emoji_six, .emoji_seven, .emoji_eight, .emoji_nine { margin-left: 5px; margin-right: 8px; }
div.preview-hint { opacity: 0.5; margin-top: 30%; margin-bottom: 30%; align-items: center; display: flex; flex-direction: column; justify-content: center; }
table.hljs-ln tr { border: none; background-color: transparent; }
table.hljs-ln tr td { border: none; background-color: transparent; }
table.hljs-ln tr td.hljs-ln-numbers { user-select: none; text-align: center; color: rgb(170, 170, 170); border-right: 1px solid rgb(204, 204, 204); vertical-align: top; padding-right: 5px; white-space: nowrap; }
table.hljs-ln tr td.hljs-ln-code { padding-left: 10px; }
::-webkit-scrollbar { background-color: rgb(234, 234, 234); width: 14px; height: 14px; border: none; }
::-webkit-scrollbar-corner { background-color: rgb(234, 234, 234); }
::-webkit-scrollbar-button { height: 14px; width: 14px; background-color: rgb(234, 234, 234); }
::-webkit-scrollbar-button:hover { background-color: rgb(208, 208, 208); }
::-webkit-scrollbar-button:active { background-color: rgb(178, 178, 178); }
::-webkit-scrollbar-track { background-color: rgb(234, 234, 234); }
::-webkit-scrollbar-thumb { border: none; background-color: rgb(218, 218, 218); }
::-webkit-scrollbar-thumb:hover { background-color: rgb(208, 208, 208); }
::-webkit-scrollbar-thumb:active { background-color: rgb(178, 178, 178); }
::-webkit-scrollbar-button:horizontal:increment { background-image: url('data:image/svg+xml;utf8,<svg width="512" height="512" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <g>    <g transform="rotate(-90 256.00000000000006,256) " id="svg_1">   <polygon fill="%23333333" id="svg_2" points="128,192 256,320 384,192  "/>  </g> </g></svg>'); background-repeat: no-repeat; background-size: contain; }
::-webkit-scrollbar-button:horizontal:decrement { background-image: url('data:image/svg+xml;utf8,<svg width="512" height="512" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <g>    <g transform="rotate(90 255.99999999999997,256.00000000000006) " id="svg_1">   <polygon points="128,192 256,320 384,192  " id="svg_2" fill="%23333333"/>  </g> </g></svg>'); background-repeat: no-repeat; background-size: contain; }
::-webkit-scrollbar-button:vertical:increment { background-image: url('data:image/svg+xml;utf8,<svg width="512" height="512" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <g>    <g transform="null" id="svg_1">   <polygon points="128,192 256,320 384,192  " id="svg_2" fill="%23333333"/>  </g> </g></svg>'); background-repeat: no-repeat; background-size: contain; }
::-webkit-scrollbar-button:vertical:decrement { background-image: url('data:image/svg+xml;utf8,<svg width="512" height="512" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <g>    <g transform="rotate(180 255.99999999999997,256) " id="svg_1">   <polygon points="128,192 256,320 384,192  " id="svg_2" fill="%23333333"/>  </g> </g></svg>'); background-repeat: no-repeat; background-size: contain; }
::selection { background: rgb(25, 118, 210); color: rgb(238, 238, 238); }
.modal-box { background-color: rgba(234, 234, 234, 0.952941); }
span.modal-close { color: rgb(102, 102, 102); }
span.modal-close:hover, span.modal-close:focus { color: rgb(34, 34, 34); }
.hljs { display: block; overflow-x: auto; padding: 0.5em; background: rgb(224, 224, 224); }
.hljs, .hljs-subst { color: rgb(54, 54, 54); }
.hljs-comment { color: rgb(118, 118, 118); }
.hljs-keyword, .hljs-attribute, .hljs-selector-tag, .hljs-meta-keyword, .hljs-doctag, .hljs-name { color: rgb(0, 0, 238); }
.hljs-type, .hljs-string, .hljs-number, .hljs-selector-id, .hljs-selector-class, .hljs-quote, .hljs-template-tag, .hljs-deletion { color: rgb(136, 0, 0); }
.hljs-title, .hljs-section { color: rgb(136, 0, 0); font-weight: bold; }
.hljs-regexp, .hljs-symbol, .hljs-variable, .hljs-template-variable, .hljs-link, .hljs-selector-attr, .hljs-selector-pseudo { color: rgb(188, 96, 96); }
.hljs-literal { color: rgb(175, 0, 215); }
.hljs-built_in, .hljs-bullet, .hljs-code, .hljs-addition { color: rgb(0, 135, 0); }
.hljs-meta { color: rgb(31, 113, 153); }
.hljs-meta-string { color: rgb(77, 153, 191); }
.hljs-emphasis { font-style: italic; }
.hljs-strong { font-weight: bold; }
.mermaid-diagram .mermaid .label { color: rgb(51, 51, 51); }
.mermaid-diagram .node rect, .mermaid-diagram .node circle, .mermaid-diagram .node ellipse, .mermaid-diagram .node polygon { fill: rgb(236, 236, 255); stroke: rgb(204, 204, 255); stroke-width: 1px; }
.mermaid-diagram .edgePath .path { stroke: rgb(51, 51, 51); }
.mermaid-diagram .edgeLabel { background-color: rgb(232, 232, 232); }
.mermaid-diagram .cluster rect { fill: rgb(255, 255, 222) !important; rx: 4 !important; stroke: rgb(170, 170, 51) !important; stroke-width: 1px !important; }
.mermaid-diagram .cluster text { fill: rgb(51, 51, 51); }
.mermaid-diagram .actor { stroke: rgb(204, 204, 255); fill: rgb(236, 236, 255); }
.mermaid-diagram text.actor { fill: black; stroke: none; }
.mermaid-diagram .actor-line { stroke: grey; }
.mermaid-diagram .messageLine0 { stroke-width: 1.5; stroke: rgb(51, 51, 51); }
.mermaid-diagram .messageLine1 { stroke-width: 1.5; stroke: rgb(51, 51, 51); }
.mermaid-diagram #arrowhead { fill: rgb(51, 51, 51); }
.mermaid-diagram #crosshead path { fill: rgb(51, 51, 51) !important; stroke: rgb(51, 51, 51) !important; }
.mermaid-diagram .messageText { fill: rgb(51, 51, 51); stroke: none; }
.mermaid-diagram .labelBox { stroke: rgb(204, 204, 255); fill: rgb(236, 236, 255); }
.mermaid-diagram .labelText { fill: black; stroke: none; }
.mermaid-diagram .loopText { fill: black; stroke: none; }
.mermaid-diagram .loopLine { stroke-width: 2; stroke: rgb(204, 204, 255); }
.mermaid-diagram .note { stroke: rgb(170, 170, 51); fill: rgb(255, 245, 173); }
.mermaid-diagram .noteText { fill: black; stroke: none; font-family: "trebuchet ms", verdana, arial; font-size: 14px; }
.mermaid-diagram .section { stroke: none; opacity: 0.2; }
.mermaid-diagram .section0 { fill: rgba(102, 102, 255, 0.490196); }
.mermaid-diagram .section2 { fill: rgb(255, 244, 0); }
.mermaid-diagram .section1, .mermaid-diagram .section3 { fill: white; opacity: 0.2; }
.mermaid-diagram .sectionTitle0 { fill: rgb(51, 51, 51); }
.mermaid-diagram .sectionTitle1 { fill: rgb(51, 51, 51); }
.mermaid-diagram .sectionTitle2 { fill: rgb(51, 51, 51); }
.mermaid-diagram .sectionTitle3 { fill: rgb(51, 51, 51); }
.mermaid-diagram .sectionTitle { text-anchor: start; font-size: 11px; }
.mermaid-diagram .grid .tick { stroke: lightgrey; opacity: 0.3; shape-rendering: crispEdges; }
.mermaid-diagram .grid path { stroke-width: 0; }
.mermaid-diagram .today { fill: none; stroke: red; stroke-width: 2px; }
.mermaid-diagram .task { stroke-width: 2; }
.mermaid-diagram .taskText { text-anchor: middle; font-size: 11px; }
.mermaid-diagram .taskTextOutsideRight { fill: black; text-anchor: start; font-size: 11px; }
.mermaid-diagram .taskTextOutsideLeft { fill: black; text-anchor: end; font-size: 11px; }
.mermaid-diagram .taskText0, .mermaid-diagram .taskText1, .mermaid-diagram .taskText2, .mermaid-diagram .taskText3 { fill: white; }
.mermaid-diagram .task0, .mermaid-diagram .task1, .mermaid-diagram .task2, .mermaid-diagram .task3 { fill: rgb(138, 144, 221); stroke: rgb(83, 79, 188); }
.mermaid-diagram .taskTextOutside0, .mermaid-diagram .taskTextOutside2 { fill: black; }
.mermaid-diagram .taskTextOutside1, .mermaid-diagram .taskTextOutside3 { fill: black; }
.mermaid-diagram .active0, .mermaid-diagram .active1, .mermaid-diagram .active2, .mermaid-diagram .active3 { fill: rgb(191, 199, 255); stroke: rgb(83, 79, 188); }
.mermaid-diagram .activeText0, .mermaid-diagram .activeText1, .mermaid-diagram .activeText2, .mermaid-diagram .activeText3 { fill: black !important; }
.mermaid-diagram .done0, .mermaid-diagram .done1, .mermaid-diagram .done2, .mermaid-diagram .done3 { stroke: grey; fill: lightgrey; stroke-width: 2; }
.mermaid-diagram .doneText0, .mermaid-diagram .doneText1, .mermaid-diagram .doneText2, .mermaid-diagram .doneText3 { fill: black !important; }
.mermaid-diagram .crit0, .mermaid-diagram .crit1, .mermaid-diagram .crit2, .mermaid-diagram .crit3 { stroke: rgb(255, 136, 136); fill: red; stroke-width: 2; }
.mermaid-diagram .activeCrit0, .mermaid-diagram .activeCrit1, .mermaid-diagram .activeCrit2, .mermaid-diagram .activeCrit3 { stroke: rgb(255, 136, 136); fill: rgb(191, 199, 255); stroke-width: 2; }
.mermaid-diagram .doneCrit0, .mermaid-diagram .doneCrit1, .mermaid-diagram .doneCrit2, .mermaid-diagram .doneCrit3 { stroke: rgb(255, 136, 136); fill: lightgrey; stroke-width: 2; cursor: pointer; shape-rendering: crispEdges; }
.mermaid-diagram .doneCritText0, .mermaid-diagram .doneCritText1, .mermaid-diagram .doneCritText2, .mermaid-diagram .doneCritText3 { fill: black !important; }
.mermaid-diagram .activeCritText0, .mermaid-diagram .activeCritText1, .mermaid-diagram .activeCritText2, .mermaid-diagram .activeCritText3 { fill: black !important; }
.mermaid-diagram .titleText { text-anchor: middle; font-size: 18px; fill: black; }
.mermaid-diagram .node text { font-family: "trebuchet ms", verdana, arial; font-size: 14px; }
.mermaid-diagram div.mermaidTooltip { position: absolute; text-align: center; max-width: 200px; padding: 2px; font-family: "trebuchet ms", verdana, arial; font-size: 12px; background: rgb(255, 255, 222); border: 1px solid rgb(170, 170, 51); border-radius: 2px; pointer-events: none; z-index: 100; }
#mermaid-diagram-1 .node > rect { }
#mermaid-diagram-1 .node text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-1 .edgeLabel text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-1 .cluster rect { fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-1 .cyan > rect, .cyan > polygon, .cyan > circle, .cyan > ellipse { fill: rgb(153, 255, 255); stroke: rgb(255, 255, 255); }
#mermaid-diagram-2 .node > rect { }
#mermaid-diagram-2 .node text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-2 .edgeLabel text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-2 .cluster rect { fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-2 .cyan > rect, .cyan > polygon, .cyan > circle, .cyan > ellipse { fill: rgb(153, 255, 255); stroke: rgb(255, 255, 255); }
#mermaid-diagram-3 .node > rect { }
#mermaid-diagram-3 .node text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-3 .edgeLabel text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-3 .cluster rect { fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-3 .cyan > rect, .cyan > polygon, .cyan > circle, .cyan > ellipse { fill: rgb(153, 255, 255); stroke: rgb(255, 255, 255); }
#mermaid-diagram-4 .node > rect { }
#mermaid-diagram-4 .node text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-4 .edgeLabel text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-4 .cluster rect { fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-4 .cyan > rect, .cyan > polygon, .cyan > circle, .cyan > ellipse { fill: rgb(153, 255, 255); stroke: rgb(255, 255, 255); }
#mermaid-diagram-5 .node > rect { }
#mermaid-diagram-5 .node text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-5 .edgeLabel text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-5 .cluster rect { fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-5 .cyan > rect, .cyan > polygon, .cyan > circle, .cyan > ellipse { fill: rgb(153, 255, 255); stroke: rgb(255, 255, 255); }
#mermaid-diagram-6 .node > rect { }
#mermaid-diagram-6 .node text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-6 .edgeLabel text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-6 .cluster rect { fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-6 .cyan > rect, .cyan > polygon, .cyan > circle, .cyan > ellipse { fill: rgb(153, 255, 255); stroke: rgb(255, 255, 255); }
#mermaid-diagram-7 .node > rect { }
#mermaid-diagram-7 .node text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-7 .edgeLabel text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-7 .cluster rect { fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-7 .cyan > rect, .cyan > polygon, .cyan > circle, .cyan > ellipse { fill: rgb(153, 255, 255); stroke: rgb(255, 255, 255); }
#mermaid-diagram-8 .node > rect { }
#mermaid-diagram-8 .node text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-8 .edgeLabel text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-8 .cluster rect { fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-8 .cyan > rect, .cyan > polygon, .cyan > circle, .cyan > ellipse { fill: rgb(153, 255, 255); stroke: rgb(255, 255, 255); }

    </style>

    <script type="text/javascript">
var toc = [];

var setVisible = function(node, visible) {
    var cl = 'hide-none';
    if (visible) {
        node.classList.remove(cl);
    } else {
        node.classList.add(cl);
    }
};

var isVisible = function(node) {
    var cl = 'hide-none';
    return !node.classList.contains(cl);
};

var setPostContentExpanded = function(node, expanded) {
    var cl = 'col-expand';
    if (expanded) {
        node.classList.add(cl);
    } else {
        node.classList.remove(cl);
    }
};

var setOutlinePanelVisible = function(visible) {
    var outlinePanel = document.getElementById('outline-panel');
    var postContent = document.getElementById('post-content');

    setVisible(outlinePanel, visible);
    setPostContentExpanded(postContent, !visible);
};

var isOutlinePanelVisible = function() {
    var outlinePanel = document.getElementById('outline-panel');
    return isVisible(outlinePanel);
};

window.addEventListener('load', function() {
    var outlinePanel = document.getElementById('outline-panel');
    outlinePanel.style.display = 'initial';

    var floatingContainer = document.getElementById('container-floating');
    floatingContainer.style.display = 'initial';

    var outlineContent = document.getElementById('outline-content');
    var postContent = document.getElementById('post-content');

    // Escape @text to Html.
    var escapeHtml = function(text) {
        var map = {
            '&': '&amp;',
            '<': '&lt;',
            '>': '&gt;',
            '"': '&quot;',
            "'": '&#039;'
        };

        return text.replace(/[&<>"']/g, function(m) { return map[m]; });
    }

    // Fetch the outline.
    var headers = postContent.querySelectorAll("h1, h2, h3, h4, h5, h6");
    toc = [];
    for (var i = 0; i < headers.length; ++i) {
        var header = headers[i];

        toc.push({
            level: parseInt(header.tagName.substr(1)),
            anchor: header.id,
            title: escapeHtml(header.textContent)
        });
    }

    if (toc.length == 0) {
        setOutlinePanelVisible(false);
        setVisible(floatingContainer, false);
        return;
    }

    var baseLevel = baseLevelOfToc(toc);
    var tocTree = tocToTree(toPerfectToc(toc, baseLevel), baseLevel);

    outlineContent.innerHTML = tocTree;
    setOutlinePanelVisible(true);
    setVisible(floatingContainer, true);
});

// Return the topest level of @toc, starting from 1.
var baseLevelOfToc = function(p_toc) {
    var level = -1;
    for (i in p_toc) {
        if (level == -1) {
            level = p_toc[i].level;
        } else if (level > p_toc[i].level) {
            level = p_toc[i].level;
        }
    }

    if (level == -1) {
        level = 1;
    }

    return level;
};

// Handle wrong title levels, such as '#' followed by '###'
var toPerfectToc = function(p_toc, p_baseLevel) {
    var i;
    var curLevel = p_baseLevel - 1;
    var perfToc = [];
    for (i in p_toc) {
        var item = p_toc[i];

        // Insert empty header.
        while (item.level > curLevel + 1) {
            curLevel += 1;
            var tmp = { level: curLevel,
                        anchor: '',
                        title: '[EMPTY]'
                      };
            perfToc.push(tmp);
        }

        perfToc.push(item);
        curLevel = item.level;
    }

    return perfToc;
};

var itemToHtml = function(item) {
    return '<a href="#' + item.anchor + '" data="' + item.anchor + '">' + item.title + '</a>';
};

// Turn a perfect toc to a tree using <ul>
var tocToTree = function(p_toc, p_baseLevel) {
    var i;
    var front = '<li>';
    var ending = ['</li>'];
    var curLevel = p_baseLevel;
    for (i in p_toc) {
        var item = p_toc[i];
        if (item.level == curLevel) {
            front += '</li>';
            front += '<li>';
            front += itemToHtml(item);
        } else if (item.level > curLevel) {
            // assert(item.level - curLevel == 1)
            front += '<ul>';
            ending.push('</ul>');
            front += '<li>';
            front += itemToHtml(item);
            ending.push('</li>');
            curLevel = item.level;
        } else {
            while (item.level < curLevel) {
                var ele = ending.pop();
                front += ele;
                if (ele == '</ul>') {
                    curLevel--;
                }
            }
            front += '</li>';
            front += '<li>';
            front += itemToHtml(item);
        }
    }
    while (ending.length > 0) {
        front += ending.pop();
    }
    front = front.replace("<li></li>", "");
    front = '<ul>' + front + '</ul>';
    return front;
};

var toggleMore = function() {
    if (toc.length == 0) {
        return;
    }

    var p = document.getElementById('floating-more');
    if (isOutlinePanelVisible()) {
        p.textContent = '<';
        setOutlinePanelVisible(false);
    } else {
        p.textContent = '>';
        setOutlinePanelVisible(true);
    }
};

window.addEventListener('scroll', function() {
    if (toc.length == 0 || !isOutlinePanelVisible()) {
        return;
    }

    var postContent = document.getElementById('post-content');
    var scrollTop = document.documentElement.scrollTop
                    || document.body.scrollTop
                    || window.pageYOffset;
    var eles = postContent.querySelectorAll("h1, h2, h3, h4, h5, h6");

    if (eles.length == 0) {
        return;
    }

    var idx = -1;
    var biaScrollTop = scrollTop + 50;
    for (var i = 0; i < eles.length; ++i) {
        if (biaScrollTop >= eles[i].offsetTop) {
            idx = i;
        } else {
            break;
        }
    }

    var header = '';
    if (idx != -1) {
        header = eles[idx].id;
    }

    highlightItemOnlyInOutline(header);
});

var highlightItemOnlyInOutline = function(id) {
    var cl = 'outline-bold';
    var outlineContent = document.getElementById('outline-content');
    var eles = outlineContent.querySelectorAll("a");
    var target = null;
    for (var i = 0; i < eles.length; ++i) {
        var ele = eles[i];
        if (ele.getAttribute('data') == id) {
            target = ele;
            ele.classList.add(cl);
        } else {
            ele.classList.remove(cl);
        }
    }

    // TODO: scroll target into view within the outline panel scroll area.
};

</script>


<!-- HEAD_PLACE_HOLDER -->
</head>
<body>
<div class="container-fluid">
<div class="row flex-xl-nowrap">
    <div id="outline-panel" style="display:none;" class="d-none d-md-block d-xl-block col-md-3 col-xl-2 bd-toc">
        <div id="outline-content" class="section-nav"></div>
    </div>
    <div id="post-content" class="col-12 col-md-9 col-xl-10 py-md-3 pl-md-5 bd-content">
    <div style="page-break-after: always;"></div>
<h1 id="toc_0">12. 客户端-服务端ORM<a class="vnote-anchor" href="#toc_0" data-anchor-icon="#"></a></h1>
<p><img src="https://github.com/wai818/mORMot-Learning/blob/master/mORMot_Picture/cartoon01.png?raw=true" alt="" class="view-image"></p>
<p>  如上所述，所有ORM功能都可以单独访问，也可以通过某些专用的客户端-服务器进程远程访问。</p>
<p>  也就是说，CRUD操作可以在数据库级别执行，也可以从TSQLRest抽象类中定义的同样的方法远程执行。</p>
<p>  这些特性有几个好处，其中包括：</p>
<ul>
<li>无需为应用程序客户端部署数据库客户端库，标准IP网络连接就足够了;</li>
<li>客户端应用程序可以安全地保持小型和独立，无需安装步骤，并且您仍然拥有本地富客户端的全部功能；</li>
<li>客户端以抽象的方式访问它们的对象，即不需要关心如何处理持久性的问题：一些类可以存储在一个SQlite3数据库中，其他类可以仅存在于服务器的内存中，其他类可以存储在外部数据库，如Oracle、Firebird、PostgreSQL、MySQL、DB2、Informix或MS SQL中；</li>
<li>只需更改类类型即可在运行时从本地访问切换到远程访问；</li>
<li>在n层架构的各个级别实现了优化，如缓存或安全性。</li>
</ul>
<h2 id="toc_1">12.1. 本地或远程ORM<a class="vnote-anchor" href="#toc_1" data-anchor-icon="#"></a></h2>
<p>  通过HTTP/1.1的典型客户端-服务端RESTful POST/Add请求实现如下：</p>
<div class="mermaid-diagram"><svg id="mermaid-diagram-1" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 533 984" style="max-width:533px;"><style type="text/css" title="mermaid-svg-internal-css">/*  */
#mermaid-diagram-1 .node&gt;rect { ; }
#mermaid-diagram-1 .node text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-1 .edgeLabel text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-1 .cluster rect  { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-1 .cyan&gt;rect, .cyan&gt;polygon, .cyan&gt;circle, .cyan&gt;ellipse { fill:#9ff;  stroke:#fff; }
/*  */
</style><g><g class="output"><g class="clusters"><g class="cluster" id="subGraph1" transform="translate(230.875,138)" style="opacity: 1;"><rect width="269.25" height="236" x="-134.625" y="-118"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-104" fill="black" stroke="none" id="mermaid-diagram-1Text" style="text-anchor: middle;"> Client</text></g><g class="cluster" id="subGraph0" transform="translate(253,649)" style="opacity: 1;"><rect width="466" height="590" x="-233" y="-295"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-281" fill="black" stroke="none" id="mermaid-diagram-1Text" style="text-anchor: middle;"> Server</text></g></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M221.70070422535213,89L181.5,138L221.70070422535213,187" marker-end="url(#arrowhead104)" style="fill:none"></path><defs><marker id="arrowhead104" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M250.67253521126761,187L275,138L250.67253521126761,89" marker-end="url(#arrowhead105)" style="fill:none"></path><defs><marker id="arrowhead105" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M197.0669014084507,423L102,472L102,543L102,602L102,661L102,720L102,779L102,838L123.32203389830508,875" marker-end="url(#arrowhead106)" style="fill:none"></path><defs><marker id="arrowhead106" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M239.75,423L239.75,472L283.7464788732394,521" marker-end="url(#arrowhead107)" style="fill:none"></path><defs><marker id="arrowhead107" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M303.5,565L303.5,602L303.5,639" marker-end="url(#arrowhead108)" style="fill:none"></path><defs><marker id="arrowhead108" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M303.5,683L303.5,720L303.5,757" marker-end="url(#arrowhead109)" style="fill:none"></path><defs><marker id="arrowhead109" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M326.6186440677966,801L365.5,838L365.5,875" marker-end="url(#arrowhead110)" style="fill:none"></path><defs><marker id="arrowhead110" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M323.2535211267606,521L367.25,472L279.25704225352115,423" marker-end="url(#arrowhead111)" style="fill:none"></path><defs><marker id="arrowhead111" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M269.10169491525426,801L211.25,838L164.0593220338983,875" marker-end="url(#arrowhead112)" style="fill:none"></path><defs><marker id="arrowhead112" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M205.6968085106383,231L167,256L167,305L167,354L205.6968085106383,379" marker-end="url(#arrowhead113)" style="fill:none"></path><defs><marker id="arrowhead113" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M261.9840425531915,379L287.25,354L287.25,305L287.25,256L261.9840425531915,231" marker-end="url(#arrowhead114)" style="fill:none"></path><defs><marker id="arrowhead114" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(181.5,138)" style="opacity: 1;"><g transform="translate(-49,-24)" class="label"><foreignObject width="98" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">ORM to JSON<br>over REST</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(275,138)" style="opacity: 1;"><g transform="translate(-24.5,-24)" class="label"><foreignObject width="49" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">return<br>new ID</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(102,661)" style="opacity: 1;"><g transform="translate(-30,-12)" class="label"><foreignObject width="60" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">dispatch</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(239.75,472)" style="opacity: 1;"><g transform="translate(-40.5,-24)" class="label"><foreignObject width="81" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">decode<br>POST JSON</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(303.5,602)" style="opacity: 1;"><g transform="translate(-36,-12)" class="label"><foreignObject width="72" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">SQL insert</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(303.5,720)" style="opacity: 1;"><g transform="translate(-64.5,-12)" class="label"><foreignObject width="129" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">prepare + execute</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(365.5,838)" style="opacity: 1;"><g transform="translate(-43.5,-12)" class="label"><foreignObject width="87" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">atomic write</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(367.25,472)" style="opacity: 1;"><g transform="translate(-67,-12)" class="label"><foreignObject width="134" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">return 200 OK + ID</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(211.25,838)" style="opacity: 1;"><g transform="translate(-48,-12)" class="label"><foreignObject width="96" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">return new ID</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(167,305)" style="opacity: 1;"><g transform="translate(-51,-24)" class="label"><foreignObject width="102" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">HTTP protocol<br>POST</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node cyan" id="C1" transform="translate(239.75,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-46.5" y="-22" width="93" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-36.5,-12)"><foreignObject width="73" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Client.Add</div></foreignObject></g></g></g><g class="node cyan" id="C2" transform="translate(239.75,209)" style="opacity: 1;"><rect rx="0" ry="0" x="-78.5" y="-22" width="157" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-68.5,-12)"><foreignObject width="137" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLHttpClient.URI</div></foreignObject></g></g></g><g class="node cyan" id="S1" transform="translate(239.75,401)" style="opacity: 1;"><rect rx="0" ry="0" x="-50" y="-22" width="100" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-40,-12)"><foreignObject width="80" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Http Server</div></foreignObject></g></g></g><g class="node cyan" id="S2" transform="translate(136,897)" style="opacity: 1;"><rect rx="0" ry="0" x="-79" y="-22" width="158" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-69,-12)"><foreignObject width="138" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLRestServer.URI</div></foreignObject></g></g></g><g class="node cyan" id="S3" transform="translate(303.5,543)" style="opacity: 1;"><rect rx="0" ry="0" x="-115.5" y="-22" width="231" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-105.5,-12)"><foreignObject width="211" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLRestServerDB.EngineAdd</div></foreignObject></g></g></g><g class="node cyan" id="S4" transform="translate(303.5,661)" style="opacity: 1;"><rect rx="0" ry="0" x="-53.5" y="-22" width="107" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-43.5,-12)"><foreignObject width="87" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">SQLite3 SQL</div></foreignObject></g></g></g><g class="node cyan" id="S5" transform="translate(303.5,779)" style="opacity: 1;"><rect rx="0" ry="0" x="-60.5" y="-22" width="121" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-50.5,-12)"><foreignObject width="101" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">SQLite3 BTREE</div></foreignObject></g></g></g><g class="node cyan" id="S6" transform="translate(365.5,897)" style="opacity: 1;"><rect rx="0" ry="0" x="-55.5" y="-22" width="111" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-45.5,-12)"><foreignObject width="91" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Database file</div></foreignObject></g></g></g></g></g></g></svg></div>
<p>  当然，可以有几个客户端访问同一台服务器。</p>
<p>  同一服务器也能够同时通过多种通信协议发布其RESTful服务，例如，HTTP/1.1用于通过网络（公司或Internet）进行远程访问，命名管道或Windows消息用于本地快速访问。</p>
<p>  上图描述了直接INSERT到服务端的SQLite3引擎，但也可以使用其他数据库后端，请参阅<a href="">数据库层</a>。</p>
<p>  通过定义<code>TSQLRestClientDB</code>类可以绕过整个客户端-服务端架构，创建独立应用程序，并将<code>TSQLRestServerDB</code>实例嵌入到可执行文件中：</p>
<div class="mermaid-diagram"><svg id="mermaid-diagram-2" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 685 650" style="max-width:685px;"><style type="text/css" title="mermaid-svg-internal-css">/*  */
#mermaid-diagram-2 .node&gt;rect { ; }
#mermaid-diagram-2 .node text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-2 .edgeLabel text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-2 .cluster rect  { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-2 .cyan&gt;rect, .cyan&gt;polygon, .cyan&gt;circle, .cyan&gt;ellipse { fill:#9ff;  stroke:#fff; }
/*  */
</style><g><g class="output"><g class="clusters"><g class="cluster" id="subGraph0" transform="translate(332.5,315)" style="opacity: 1;"><rect width="625" height="590" x="-312.5" y="-295"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-281" fill="black" stroke="none" id="mermaid-diagram-2Text" style="text-anchor: middle;"> Stand-Alone application</text></g></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M234.4612676056338,89L142.5,138L142.5,209L142.5,268L142.5,327L142.5,386L142.5,423" marker-end="url(#arrowhead187)" style="fill:none"></path><defs><marker id="arrowhead187" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M142.5,467L142.5,504L266.6694915254237,541" marker-end="url(#arrowhead188)" style="fill:none"></path><defs><marker id="arrowhead188" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M295.8133802816901,89L340.5,138L340.5,187" marker-end="url(#arrowhead189)" style="fill:none"></path><defs><marker id="arrowhead189" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M340.5,231L340.5,268L340.5,305" marker-end="url(#arrowhead190)" style="fill:none"></path><defs><marker id="arrowhead190" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M340.5,349L340.5,386L340.5,423" marker-end="url(#arrowhead191)" style="fill:none"></path><defs><marker id="arrowhead191" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M401,461.6799065420561L554.5,504L554.5,541" marker-end="url(#arrowhead192)" style="fill:none"></path><defs><marker id="arrowhead192" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M340.5,467L340.5,504L340.5,541" marker-end="url(#arrowhead193)" style="fill:none"></path><defs><marker id="arrowhead193" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M396.6186440677966,541L491,504L491,445L491,386L491,327L491,268L491,209L491,138L322.25,82.33797909407666" marker-end="url(#arrowhead194)" style="fill:none"></path><defs><marker id="arrowhead194" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(142.5,268)" style="opacity: 1;"><g transform="translate(-86,-12)" class="label"><foreignObject width="172" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">ORM to JSON over REST</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(142.5,504)" style="opacity: 1;"><g transform="translate(-34,-12)" class="label"><foreignObject width="68" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">direct call</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(340.5,138)" style="opacity: 1;"><g transform="translate(-40.5,-24)" class="label"><foreignObject width="81" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">decode<br>POST JSON</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(340.5,268)" style="opacity: 1;"><g transform="translate(-36,-12)" class="label"><foreignObject width="72" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">SQL insert</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(340.5,386)" style="opacity: 1;"><g transform="translate(-64.5,-12)" class="label"><foreignObject width="129" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">prepare + execute</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(554.5,504)" style="opacity: 1;"><g transform="translate(-43.5,-12)" class="label"><foreignObject width="87" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">atomic write</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(340.5,504)" style="opacity: 1;"><g transform="translate(-48,-12)" class="label"><foreignObject width="96" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">return new ID</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(491,327)" style="opacity: 1;"><g transform="translate(-48,-12)" class="label"><foreignObject width="96" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">return new ID</span></div></foreignObject></g></g></g><g class="nodes"><g class="node cyan" id="A" transform="translate(275.75,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-46.5" y="-22" width="93" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-36.5,-12)"><foreignObject width="73" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Client.Add</div></foreignObject></g></g></g><g class="node cyan" id="B" transform="translate(142.5,445)" style="opacity: 1;"><rect rx="0" ry="0" x="-87.5" y="-22" width="175" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-77.5,-12)"><foreignObject width="155" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLRestClientDB.URI</div></foreignObject></g></g></g><g class="node cyan" id="C" transform="translate(340.5,563)" style="opacity: 1;"><rect rx="0" ry="0" x="-89.5" y="-22" width="179" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-79.5,-12)"><foreignObject width="159" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLRestServerDB.URI</div></foreignObject></g></g></g><g class="node cyan" id="D" transform="translate(340.5,209)" style="opacity: 1;"><rect rx="0" ry="0" x="-115.5" y="-22" width="231" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-105.5,-12)"><foreignObject width="211" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLRestServerDB.EngineAdd</div></foreignObject></g></g></g><g class="node cyan" id="E" transform="translate(340.5,327)" style="opacity: 1;"><rect rx="0" ry="0" x="-53.5" y="-22" width="107" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-43.5,-12)"><foreignObject width="87" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">SQLite3 SQL</div></foreignObject></g></g></g><g class="node cyan" id="F" transform="translate(340.5,445)" style="opacity: 1;"><rect rx="0" ry="0" x="-60.5" y="-22" width="121" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-50.5,-12)"><foreignObject width="101" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">SQLite3 BTREE</div></foreignObject></g></g></g><g class="node cyan" id="G" transform="translate(554.5,563)" style="opacity: 1;"><rect rx="0" ry="0" x="-55.5" y="-22" width="111" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-45.5,-12)"><foreignObject width="91" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Database file</div></foreignObject></g></g></g></g></g></g></svg></div>
<p>  事实上，同样的可执行文件可以作为服务端、独立应用、客户端应用程序启动！ 这只是如何初始化<code>TSQLRest</code>类实例的问题，请参阅<a href="">客户端-服务器进程</a>。 一些mORMot用户使用此特性来简化部署、支持和配置。 它在调试时也非常有用，因为您可以在IDE中使用同一个应用程序运行项目的服务端和客户端。</p>
<p>  如果使用虚拟表（内存或访问外部数据库），客户端保持不变，只有服务端需要根据<a href="">ORM处理外部数据库</a>的描述进行修改：</p>
<div class="mermaid-diagram"><svg id="mermaid-diagram-3" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 736.5 1336" style="max-width:736.5px;"><style type="text/css" title="mermaid-svg-internal-css">/*  */
#mermaid-diagram-3 .node&gt;rect { ; }
#mermaid-diagram-3 .node text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-3 .edgeLabel text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-3 .cluster rect  { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-3 .cyan&gt;rect, .cyan&gt;polygon, .cyan&gt;circle, .cyan&gt;ellipse { fill:#9ff;  stroke:#fff; }
/*  */
</style><g><g class="output"><g class="clusters"><g class="cluster" id="subGraph0" transform="translate(358.25,658)" style="opacity: 1;"><rect width="676.5" height="1276" x="-338.25" y="-638"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-624" fill="black" stroke="none" id="mermaid-diagram-3Text" style="text-anchor: middle;"> Server</text></g></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M321.25,78.75298804780877L120.25,126L292.25,166.43027888446215" marker-end="url(#arrowhead331)" style="fill:none"></path><defs><marker id="arrowhead331" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M450.25,163.4212962962963L587.25,126L421.25,80.6574074074074" marker-end="url(#arrowhead332)" style="fill:none"></path><defs><marker id="arrowhead332" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M309.0457746478873,207L170.5,256L170.5,305" marker-end="url(#arrowhead333)" style="fill:none"></path><defs><marker id="arrowhead333" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M170.5,349L170.5,398L170.5,447" marker-end="url(#arrowhead334)" style="fill:none"></path><defs><marker id="arrowhead334" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M170.5,491L170.5,528L170.5,565" marker-end="url(#arrowhead335)" style="fill:none"></path><defs><marker id="arrowhead335" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M170.5,609L170.5,646L217.6906779661017,683" marker-end="url(#arrowhead336)" style="fill:none"></path><defs><marker id="arrowhead336" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M234,603.2186147186147L401.5,646L492.1186440677966,683" marker-end="url(#arrowhead337)" style="fill:none"></path><defs><marker id="arrowhead337" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M245.75,727L245.75,776L245.75,825" marker-end="url(#arrowhead338)" style="fill:none"></path><defs><marker id="arrowhead338" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M522.8380281690141,727L471.25,776L471.25,825" marker-end="url(#arrowhead339)" style="fill:none"></path><defs><marker id="arrowhead339" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M471.25,869L471.25,906L518.1271186440678,943" marker-end="url(#arrowhead340)" style="fill:none"></path><defs><marker id="arrowhead340" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M573.8728813559322,943L620.75,906L620.75,847L620.75,776L569.1619718309859,727" marker-end="url(#arrowhead341)" style="fill:none"></path><defs><marker id="arrowhead341" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M471.5,981.9671210906175L234.25,1036L458.5,1087.0721732157176" marker-end="url(#arrowhead342)" style="fill:none"></path><defs><marker id="arrowhead342" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M569.1619718309859,1085L620.75,1036L569.1619718309859,987" marker-end="url(#arrowhead343)" style="fill:none"></path><defs><marker id="arrowhead343" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M458.5,1126.6442687747035L229.75,1178L480.5,1234.294861660079" marker-end="url(#arrowhead344)" style="fill:none"></path><defs><marker id="arrowhead344" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M569.1619718309859,1227L620.75,1178L569.1619718309859,1129" marker-end="url(#arrowhead345)" style="fill:none"></path><defs><marker id="arrowhead345" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M273.8093220338983,683L321,646L321,587L321,528L321,469L321,398L321,327L321,256L355.67957746478874,207" marker-end="url(#arrowhead346)" style="fill:none"></path><defs><marker id="arrowhead346" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M564.9237288135594,683L596.75,646L596.75,587L596.75,528L596.75,469L596.75,398L596.75,327L596.75,256L441.1232394366197,207" marker-end="url(#arrowhead347)" style="fill:none"></path><defs><marker id="arrowhead347" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(120.25,126)" style="opacity: 1;"><g transform="translate(-30,-12)" class="label"><foreignObject width="60" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">dispatch</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(587.25,126)" style="opacity: 1;"><g transform="translate(-67,-12)" class="label"><foreignObject width="134" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">return 200 OK + ID</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(170.5,256)" style="opacity: 1;"><g transform="translate(-40.5,-24)" class="label"><foreignObject width="81" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">decode<br>POST JSON</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(170.5,398)" style="opacity: 1;"><g transform="translate(-19.5,-24)" class="label"><foreignObject width="39" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">SQL<br>insert</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(170.5,528)" style="opacity: 1;"><g transform="translate(-64.5,-12)" class="label"><foreignObject width="129" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">prepare + execute</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(170.5,646)" style="opacity: 1;"><g transform="translate(-64.5,-12)" class="label"><foreignObject width="129" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">Is a SQLite3 table?</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(401.5,646)" style="opacity: 1;"><g transform="translate(-60.5,-12)" class="label"><foreignObject width="121" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">Is a Virtual table?</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(245.75,776)" style="opacity: 1;"><g transform="translate(-24,-24)" class="label"><foreignObject width="48" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">atomic<br>write</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(471.25,776)" style="opacity: 1;"><g transform="translate(-32,-24)" class="label"><foreignObject width="64" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">external<br>database</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(471.25,906)" style="opacity: 1;"><g transform="translate(-69.5,-12)" class="label"><foreignObject width="139" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">compute SQL insert</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(234.25,1036)" style="opacity: 1;"><g transform="translate(-27,-24)" class="label"><foreignObject width="54" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">execute<br>SQL</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(229.75,1178)" style="opacity: 1;"><g transform="translate(-18,-24)" class="label"><foreignObject width="36" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">store<br>data</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(321,469)" style="opacity: 1;"><g transform="translate(-48,-12)" class="label"><foreignObject width="96" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">return new ID</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(596.75,469)" style="opacity: 1;"><g transform="translate(-48,-12)" class="label"><foreignObject width="96" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">return new ID</span></div></foreignObject></g></g></g><g class="nodes"><g class="node cyan" id="A1" transform="translate(371.25,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-50" y="-22" width="100" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-40,-12)"><foreignObject width="80" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Http Server</div></foreignObject></g></g></g><g class="node cyan" id="A2" transform="translate(371.25,185)" style="opacity: 1;"><rect rx="0" ry="0" x="-79" y="-22" width="158" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-69,-12)"><foreignObject width="138" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLRestServer.URI</div></foreignObject></g></g></g><g class="node cyan" id="A3" transform="translate(170.5,327)" style="opacity: 1;"><rect rx="0" ry="0" x="-115.5" y="-22" width="231" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-105.5,-12)"><foreignObject width="211" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLRestServerDB.EngineAdd</div></foreignObject></g></g></g><g class="node cyan" id="A4" transform="translate(170.5,469)" style="opacity: 1;"><rect rx="0" ry="0" x="-53.5" y="-22" width="107" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-43.5,-12)"><foreignObject width="87" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">SQLite3 SQL</div></foreignObject></g></g></g><g class="node cyan" id="A5" transform="translate(170.5,587)" style="opacity: 1;"><rect rx="0" ry="0" x="-63.5" y="-22" width="127" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-53.5,-12)"><foreignObject width="107" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">SQLite3 engine</div></foreignObject></g></g></g><g class="node cyan" id="A6" transform="translate(245.75,705)" style="opacity: 1;"><rect rx="0" ry="0" x="-60.5" y="-22" width="121" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-50.5,-12)"><foreignObject width="101" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">SQLite3 BTREE</div></foreignObject></g></g></g><g class="node cyan" id="A7" transform="translate(546,705)" style="opacity: 1;"><rect rx="0" ry="0" x="-96.5" y="-22" width="193" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-86.5,-12)"><foreignObject width="173" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLVirtualTableExternal</div></foreignObject></g></g></g><g class="node cyan" id="A8" transform="translate(245.75,847)" style="opacity: 1;"><rect rx="0" ry="0" x="-55.5" y="-22" width="111" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-45.5,-12)"><foreignObject width="91" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Database file</div></foreignObject></g></g></g><g class="node cyan" id="A9" transform="translate(471.25,847)" style="opacity: 1;"><rect rx="0" ry="0" x="-114.5" y="-22" width="229" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-104.5,-12)"><foreignObject width="209" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLDBConnectionProperties</div></foreignObject></g></g></g><g class="node cyan" id="A10" transform="translate(546,965)" style="opacity: 1;"><rect rx="0" ry="0" x="-74.5" y="-22" width="149" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-64.5,-12)"><foreignObject width="129" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLDBStatement</div></foreignObject></g></g></g><g class="node cyan" id="A11" transform="translate(546,1107)" style="opacity: 1;"><rect rx="0" ry="0" x="-87.5" y="-22" width="175" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-77.5,-12)"><foreignObject width="155" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">OleDB/ODBC or other</div></foreignObject></g></g></g><g class="node cyan" id="A12" transform="translate(546,1249)" style="opacity: 1;"><rect rx="0" ry="0" x="-65.5" y="-22" width="131" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-55.5,-12)"><foreignObject width="111" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Database Client</div></foreignObject></g></g></g></g></g></g></svg></div>
<p>  实际上，上述功能对应于仅具有外部虚拟表的数据库模型，并使用<code>StaticVirtualTableDirect = false</code>，即为每个请求调用SQlite3的虚拟表机制。</p>
<p>  但大多数情况下，对于RESTful / CRUD命令，如下的执行更直接：</p>
<div class="mermaid-diagram"><svg id="mermaid-diagram-4" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 814.75 862" style="max-width:814.75px;"><style type="text/css" title="mermaid-svg-internal-css">/*  */
#mermaid-diagram-4 .node&gt;rect { ; }
#mermaid-diagram-4 .node text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-4 .edgeLabel text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-4 .cluster rect  { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-4 .cyan&gt;rect, .cyan&gt;polygon, .cyan&gt;circle, .cyan&gt;ellipse { fill:#9ff;  stroke:#fff; }
/*  */
</style><g><g class="output"><g class="clusters"><g class="cluster" id="subGraph0" transform="translate(397.375,421)" style="opacity: 1;"><rect width="754.75" height="802" x="-377.375" y="-401"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-387" fill="black" stroke="none" id="mermaid-diagram-4Text" style="text-anchor: middle;"> Server</text></g></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M308,79.40799158780231L120.25,126L279,165.39537329127234" marker-end="url(#arrowhead454)" style="fill:none"></path><defs><marker id="arrowhead454" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M437,168.74542284219703L644.75,126L408,77.2877070619006" marker-end="url(#arrowhead455)" style="fill:none"></path><defs><marker id="arrowhead455" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M288.08474576271186,207L170.5,244L170.5,281" marker-end="url(#arrowhead456)" style="fill:none"></path><defs><marker id="arrowhead456" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M394.8220338983051,207L456.75,244L542.3516949152543,281" marker-end="url(#arrowhead457)" style="fill:none"></path><defs><marker id="arrowhead457" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M170.5,325L170.5,362L170.5,399" marker-end="url(#arrowhead458)" style="fill:none"></path><defs><marker id="arrowhead458" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M170.5,443L170.5,480L170.5,517" marker-end="url(#arrowhead459)" style="fill:none"></path><defs><marker id="arrowhead459" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M170.5,561L170.5,598L217.6906779661017,635" marker-end="url(#arrowhead460)" style="fill:none"></path><defs><marker id="arrowhead460" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M245.75,679L245.75,716L245.75,753" marker-end="url(#arrowhead461)" style="fill:none"></path><defs><marker id="arrowhead461" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M273.8093220338983,635L321,598L321,539L321,480L321,421L321,362L321,303L321,244L344.20338983050846,207" marker-end="url(#arrowhead462)" style="fill:none"></path><defs><marker id="arrowhead462" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M615.9957627118644,281L654.25,244L437,200.73333333333332" marker-end="url(#arrowhead463)" style="fill:none"></path><defs><marker id="arrowhead463" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M565.3771186440678,325L518.5,362L518.5,399" marker-end="url(#arrowhead464)" style="fill:none"></path><defs><marker id="arrowhead464" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M518.5,443L518.5,480L565.3771186440678,517" marker-end="url(#arrowhead465)" style="fill:none"></path><defs><marker id="arrowhead465" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M624.9449152542372,517L678.25,480L678.25,421L678.25,362L624.9449152542372,325" marker-end="url(#arrowhead466)" style="fill:none"></path><defs><marker id="arrowhead466" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M540.3940677966102,561L451.5,598L540.3940677966102,635" marker-end="url(#arrowhead467)" style="fill:none"></path><defs><marker id="arrowhead467" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M624.9449152542372,635L678.25,598L624.9449152542372,561" marker-end="url(#arrowhead468)" style="fill:none"></path><defs><marker id="arrowhead468" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M547.0127118644068,679L469.25,716L547.0127118644068,753" marker-end="url(#arrowhead469)" style="fill:none"></path><defs><marker id="arrowhead469" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M624.9449152542372,753L678.25,716L624.9449152542372,679" marker-end="url(#arrowhead470)" style="fill:none"></path><defs><marker id="arrowhead470" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(120.25,126)" style="opacity: 1;"><g transform="translate(-30,-12)" class="label"><foreignObject width="60" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">dispatch</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(644.75,126)" style="opacity: 1;"><g transform="translate(-67,-12)" class="label"><foreignObject width="134" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">return 200 OK + ID</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(170.5,244)" style="opacity: 1;"><g transform="translate(-64.5,-12)" class="label"><foreignObject width="129" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">Is a SQLite3 table?</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(456.75,244)" style="opacity: 1;"><g transform="translate(-54,-12)" class="label"><foreignObject width="108" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">s a static table?</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(170.5,362)" style="opacity: 1;"><g transform="translate(-36,-12)" class="label"><foreignObject width="72" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">SQL insert</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(170.5,480)" style="opacity: 1;"><g transform="translate(-64.5,-12)" class="label"><foreignObject width="129" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">Is a SQLite3 table?</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(170.5,598)" style="opacity: 1;"><g transform="translate(-64.5,-12)" class="label"><foreignObject width="129" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">prepare + execute</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(245.75,716)" style="opacity: 1;"><g transform="translate(-43.5,-12)" class="label"><foreignObject width="87" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">atomic write</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(321,421)" style="opacity: 1;"><g transform="translate(-48,-12)" class="label"><foreignObject width="96" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">return new ID</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(654.25,244)" style="opacity: 1;"><g transform="translate(-48,-12)" class="label"><foreignObject width="96" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">return new ID</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(518.5,362)" style="opacity: 1;"><g transform="translate(-62,-12)" class="label"><foreignObject width="124" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">external database</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(518.5,480)" style="opacity: 1;"><g transform="translate(-47.5,-12)" class="label"><foreignObject width="95" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">compute SQL</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(451.5,598)" style="opacity: 1;"><g transform="translate(-43.5,-12)" class="label"><foreignObject width="87" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">execute SQL</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(469.25,716)" style="opacity: 1;"><g transform="translate(-35.5,-12)" class="label"><foreignObject width="71" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">store data</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node cyan" id="A" transform="translate(358,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-50" y="-22" width="100" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-40,-12)"><foreignObject width="80" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Http Server</div></foreignObject></g></g></g><g class="node cyan" id="B" transform="translate(358,185)" style="opacity: 1;"><rect rx="0" ry="0" x="-79" y="-22" width="158" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-69,-12)"><foreignObject width="138" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLRestServer.URI</div></foreignObject></g></g></g><g class="node cyan" id="C1" transform="translate(170.5,303)" style="opacity: 1;"><rect rx="0" ry="0" x="-115.5" y="-22" width="231" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-105.5,-12)"><foreignObject width="211" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLRestServerDB.EngineAdd</div></foreignObject></g></g></g><g class="node cyan" id="C2" transform="translate(170.5,421)" style="opacity: 1;"><rect rx="0" ry="0" x="-53.5" y="-22" width="107" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-43.5,-12)"><foreignObject width="87" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">SQLite3 SQL</div></foreignObject></g></g></g><g class="node cyan" id="C3" transform="translate(170.5,539)" style="opacity: 1;"><rect rx="0" ry="0" x="-63.5" y="-22" width="127" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-53.5,-12)"><foreignObject width="107" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">SQLite3 engine</div></foreignObject></g></g></g><g class="node cyan" id="C4" transform="translate(245.75,657)" style="opacity: 1;"><rect rx="0" ry="0" x="-60.5" y="-22" width="121" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-50.5,-12)"><foreignObject width="101" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">SQLite3 BTREE</div></foreignObject></g></g></g><g class="node cyan" id="C5" transform="translate(245.75,775)" style="opacity: 1;"><rect rx="0" ry="0" x="-55.5" y="-22" width="111" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-45.5,-12)"><foreignObject width="91" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Database file</div></foreignObject></g></g></g><g class="node cyan" id="D1" transform="translate(593.25,303)" style="opacity: 1;"><rect rx="0" ry="0" x="-138" y="-22" width="276" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-128,-12)"><foreignObject width="256" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLRestStorageExternal.EngineAdd</div></foreignObject></g></g></g><g class="node cyan" id="D2" transform="translate(518.5,421)" style="opacity: 1;"><rect rx="0" ry="0" x="-114.5" y="-22" width="229" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-104.5,-12)"><foreignObject width="209" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLDBConnectionProperties</div></foreignObject></g></g></g><g class="node cyan" id="D3" transform="translate(593.25,539)" style="opacity: 1;"><rect rx="0" ry="0" x="-74.5" y="-22" width="149" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-64.5,-12)"><foreignObject width="129" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLDBStatement</div></foreignObject></g></g></g><g class="node cyan" id="D4" transform="translate(593.25,657)" style="opacity: 1;"><rect rx="0" ry="0" x="-87.5" y="-22" width="175" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-77.5,-12)"><foreignObject width="155" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">OleDB/ODBC or other</div></foreignObject></g></g></g><g class="node cyan" id="D5" transform="translate(593.25,775)" style="opacity: 1;"><rect rx="0" ry="0" x="-65.5" y="-22" width="131" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-55.5,-12)"><foreignObject width="111" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Database Client</div></foreignObject></g></g></g></g></g></g></svg></div>
<p>  如<a href="">外部SQL数据库访问</a>所述，调用静态<code>TSQLRestStorageExternal</code>实例适用于大多数RESTful访问。 实际上，与直接数据库访问相比，这种设计不会导致速度损失。 如果服务器与数据库位于同一台计算机上，在这种情况下，使用JSON和REST可能会更快，甚至比批量模式更快。</p>
<p>  为了详尽无遗，这里有一个更完整的图表，显示了如何在服务器端处理本地SQLite3、内存或外部表。 您将了解如何直接处理CRUD语句以获得更好的速度，而任何SQL JOIN查询也可以在所有类型的表中进行处理。</p>
<div class="mermaid-diagram"><svg id="mermaid-diagram-5" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 1776.5 1552" style="max-width:1776.5px;"><style type="text/css" title="mermaid-svg-internal-css">/*  */
#mermaid-diagram-5 .node&gt;rect { ; }
#mermaid-diagram-5 .node text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-5 .edgeLabel text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-5 .cluster rect  { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-5 .cyan&gt;rect, .cyan&gt;polygon, .cyan&gt;circle, .cyan&gt;ellipse { fill:#9ff;  stroke:#fff; }
/*  */
</style><g><g class="output"><g class="clusters"><g class="cluster" id="subGraph0" transform="translate(878.25,766)" style="opacity: 1;"><rect width="1716.5" height="1492" x="-858.25" y="-746"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-732" fill="black" stroke="none" id="mermaid-diagram-5Text" style="text-anchor: middle;"> Server</text></g></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M917.75,71.1004909038406L102,138L888.75,202.52122437193185" marker-end="url(#arrowhead647)" style="fill:none"></path><defs><marker id="arrowhead647" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1046.75,200.0004011231448L1591,138L1017.75,72.69594865623746" marker-end="url(#arrowhead648)" style="fill:none"></path><defs><marker id="arrowhead648" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M888.75,216.85504642108415L133,292L133,353" marker-end="url(#arrowhead649)" style="fill:none"></path><defs><marker id="arrowhead649" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M985.5753012048193,231L1035,292L1035,353" marker-end="url(#arrowhead650)" style="fill:none"></path><defs><marker id="arrowhead650" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M133,421L133,470L133,531" marker-end="url(#arrowhead651)" style="fill:none"></path><defs><marker id="arrowhead651" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M963,399.41121495327104L553.5,470L553.5,519" marker-end="url(#arrowhead652)" style="fill:none"></path><defs><marker id="arrowhead652" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M968.3313253012049,421L872.25,470L872.25,519" marker-end="url(#arrowhead653)" style="fill:none"></path><defs><marker id="arrowhead653" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1081.3915662650602,421L1148.25,470L1148.25,519" marker-end="url(#arrowhead654)" style="fill:none"></path><defs><marker id="arrowhead654" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1107,403.3167235494881L1401.25,470L1401.25,519" marker-end="url(#arrowhead655)" style="fill:none"></path><defs><marker id="arrowhead655" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M133,575L133,624L246.9156626506024,685" marker-end="url(#arrowhead656)" style="fill:none"></path><defs><marker id="arrowhead656" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M553.5,587L553.5,624L585.3734939759036,661" marker-end="url(#arrowhead657)" style="fill:none"></path><defs><marker id="arrowhead657" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M872.25,587L872.25,624L872.25,673" marker-end="url(#arrowhead658)" style="fill:none"></path><defs><marker id="arrowhead658" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1148.25,587L1148.25,624L1148.25,673" marker-end="url(#arrowhead659)" style="fill:none"></path><defs><marker id="arrowhead659" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1401.25,587L1401.25,624L1443.460843373494,673" marker-end="url(#arrowhead660)" style="fill:none"></path><defs><marker id="arrowhead660" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M247.5467289719626,729L91.25,814L109.88421052631578,887" marker-end="url(#arrowhead661)" style="fill:none"></path><defs><marker id="arrowhead661" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M320.4698795180723,685L410.5,624L410.5,553L410.5,470L410.5,387L410.5,292L888.75,220.766711529834" marker-end="url(#arrowhead662)" style="fill:none"></path><defs><marker id="arrowhead662" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M293.85981308411215,729L316.5,814L316.5,875" marker-end="url(#arrowhead663)" style="fill:none"></path><defs><marker id="arrowhead663" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M351.5,727.1318518518518L625.5,814L625.5,887" marker-end="url(#arrowhead664)" style="fill:none"></path><defs><marker id="arrowhead664" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M664.6265060240964,661L696.5,624L696.5,553L696.5,470L696.5,387L696.5,292L895.8524096385543,231" marker-end="url(#arrowhead665)" style="fill:none"></path><defs><marker id="arrowhead665" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M872.25,741L872.25,814L1231.75,896.0973557692307" marker-end="url(#arrowhead666)" style="fill:none"></path><defs><marker id="arrowhead666" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1502.039156626506,673L1544.25,624L1544.25,553L1544.25,470L1544.25,387L1544.25,292L1046.75,220.37380745880313" marker-end="url(#arrowhead667)" style="fill:none"></path><defs><marker id="arrowhead667" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M115.5,931L115.5,992L115.5,1065" marker-end="url(#arrowhead668)" style="fill:none"></path><defs><marker id="arrowhead668" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M128.7,887L172.5,814L264.25233644859816,729" marker-end="url(#arrowhead669)" style="fill:none"></path><defs><marker id="arrowhead669" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M316.5,943L316.5,992L348.86578947368423,1041" marker-end="url(#arrowhead670)" style="fill:none"></path><defs><marker id="arrowhead670" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M625.5,931L625.5,992L625.5,1065" marker-end="url(#arrowhead671)" style="fill:none"></path><defs><marker id="arrowhead671" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1231.75,918.1547096144461L776,992L1245.25,1079.0253782332845" marker-end="url(#arrowhead672)" style="fill:none"></path><defs><marker id="arrowhead672" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1344.75,892.2918287937744L1609.5,814L1609.5,707L1609.5,624L1609.5,553L1609.5,470L1609.5,387L1609.5,292L1046.75,219.21737436696532" marker-end="url(#arrowhead673)" style="fill:none"></path><defs><marker id="arrowhead673" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M414.11315789473684,1041L451.25,992L451.25,909L451.25,814L321.56542056074767,729" marker-end="url(#arrowhead674)" style="fill:none"></path><defs><marker id="arrowhead674" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M625.5,1109L625.5,1170L1155.75,1221.7317073170732" marker-end="url(#arrowhead675)" style="fill:none"></path><defs><marker id="arrowhead675" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1331.25,1074.284046692607L1609.5,992L1344.75,923.5976653696498" marker-end="url(#arrowhead676)" style="fill:none"></path><defs><marker id="arrowhead676" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1155.75,1233.9249299719888L337.75,1288L1142.75,1341.2156862745098" marker-end="url(#arrowhead677)" style="fill:none"></path><defs><marker id="arrowhead677" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1304.75,1218.8954022988505L1665.25,1170L1665.25,1087L1665.25,992L1665.25,909L1665.25,814L351.5,711.9333817389726" marker-end="url(#arrowhead678)" style="fill:none"></path><defs><marker id="arrowhead678" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1142.75,1352.7778399552321L336.75,1406L1164.75,1460.6748740906548" marker-end="url(#arrowhead679)" style="fill:none"></path><defs><marker id="arrowhead679" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1317.75,1335.132183908046L1665.25,1288L1304.75,1239.1045977011495" marker-end="url(#arrowhead680)" style="fill:none"></path><defs><marker id="arrowhead680" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1295.75,1456.116091954023L1665.25,1406L1317.75,1358.867816091954" marker-end="url(#arrowhead681)" style="fill:none"></path><defs><marker id="arrowhead681" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(102,138)" style="opacity: 1;"><g transform="translate(-30,-12)" class="label"><foreignObject width="60" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">dispatch</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(1591,138)" style="opacity: 1;"><g transform="translate(-57,-24)" class="label"><foreignObject width="114" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">return 200 OK +<br>result (JSON)</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(133,292)" style="opacity: 1;"><g transform="translate(-63,-36)" class="label"><foreignObject width="126" height="72"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">Refers to<br>a SQLite3 table or<br>a JOINed query?</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(1035,292)" style="opacity: 1;"><g transform="translate(-48,-24)" class="label"><foreignObject width="96" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">CRUD over<br>a static table?</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(133,470)" style="opacity: 1;"><g transform="translate(-58.5,-12)" class="label"><foreignObject width="117" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">decode into SQL</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(553.5,470)" style="opacity: 1;"><g transform="translate(-81,-24)" class="label"><foreignObject width="162" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">Is an in-memory table?<br>(Virtual or static)</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(872.25,470)" style="opacity: 1;"><g transform="translate(-47,-24)" class="label"><foreignObject width="94" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">Is an external<br>Virtual Table?</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(1148.25,470)" style="opacity: 1;"><g transform="translate(-73,-12)" class="label"><foreignObject width="146" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">Is a redirected table?</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(1401.25,470)" style="opacity: 1;"><g transform="translate(-73.5,-12)" class="label"><foreignObject width="147" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">Is a MongoDB table?</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(133,624)" style="opacity: 1;"><g transform="translate(-64.5,-12)" class="label"><foreignObject width="129" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">prepare + execute</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(872.25,624)" style="opacity: 1;"><g transform="translate(-47.5,-12)" class="label"><foreignObject width="95" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">compute SQL</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(91.25,814)" style="opacity: 1;"><g transform="translate(-27,-36)" class="label"><foreignObject width="54" height="72"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">For any<br>SQLite3<br>table</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(316.5,814)" style="opacity: 1;"><g transform="translate(-67,-24)" class="label"><foreignObject width="134" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">For any in-memory<br>Virtual Table</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(625.5,814)" style="opacity: 1;"><g transform="translate(-56.5,-24)" class="label"><foreignObject width="113" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">For any external<br>Virtual table</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(872.25,814)" style="opacity: 1;"><g transform="translate(-39,-12)" class="label"><foreignObject width="78" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">xecute SQL</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(115.5,992)" style="opacity: 1;"><g transform="translate(-36.5,-24)" class="label"><foreignObject width="73" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">tomic<br>read/write</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(625.5,992)" style="opacity: 1;"><g transform="translate(-32,-24)" class="label"><foreignObject width="64" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">external<br>database</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(776,992)" style="opacity: 1;"><g transform="translate(-41.5,-12)" class="label"><foreignObject width="83" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">handle data</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(625.5,1170)" style="opacity: 1;"><g transform="translate(-47.5,-12)" class="label"><foreignObject width="95" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">compute SQL</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(337.75,1288)" style="opacity: 1;"><g transform="translate(-43.5,-12)" class="label"><foreignObject width="87" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">execute SQL</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(336.75,1406)" style="opacity: 1;"><g transform="translate(-41.5,-12)" class="label"><foreignObject width="83" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">handle data</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node cyan" id="A" transform="translate(967.75,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-50" y="-22" width="100" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-40,-12)"><foreignObject width="80" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Http Server</div></foreignObject></g></g></g><g class="node cyan" id="B" transform="translate(967.75,209)" style="opacity: 1;"><rect rx="0" ry="0" x="-79" y="-22" width="158" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-69,-12)"><foreignObject width="138" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLRestServer.URI</div></foreignObject></g></g></g><g class="node cyan" id="C1" transform="translate(133,387)" style="opacity: 1;"><rect rx="0" ry="0" x="-77" y="-34" width="154" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-67,-24)"><foreignObject width="134" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLRestServerDB.<br>Engine*</div></foreignObject></g></g></g><g class="node cyan" id="C2" transform="translate(1035,387)" style="opacity: 1;"><rect rx="0" ry="0" x="-72" y="-34" width="144" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-62,-24)"><foreignObject width="124" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLRestStorage.<br>Engine</div></foreignObject></g></g></g><g class="node cyan" id="D1" transform="translate(133,553)" style="opacity: 1;"><rect rx="0" ry="0" x="-53.5" y="-22" width="107" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-43.5,-12)"><foreignObject width="87" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">SQLite3 SQL</div></foreignObject></g></g></g><g class="node cyan" id="D2" transform="translate(553.5,553)" style="opacity: 1;"><rect rx="0" ry="0" x="-108" y="-34" width="216" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-98,-24)"><foreignObject width="196" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLRestStorageInMemory.<br>Engine*</div></foreignObject></g></g></g><g class="node cyan" id="D3" transform="translate(872.25,553)" style="opacity: 1;"><rect rx="0" ry="0" x="-99.5" y="-34" width="199" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-89.5,-24)"><foreignObject width="179" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLRestStorageExternal.<br>Engine*</div></foreignObject></g></g></g><g class="node cyan" id="D4" transform="translate(1148.25,553)" style="opacity: 1;"><rect rx="0" ry="0" x="-95" y="-34" width="190" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-85,-24)"><foreignObject width="170" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">SQLRestStorageRemote.<br>Engine*</div></foreignObject></g></g></g><g class="node cyan" id="D5" transform="translate(1401.25,553)" style="opacity: 1;"><rect rx="0" ry="0" x="-108" y="-34" width="216" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-98,-24)"><foreignObject width="196" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLRestStorageMongoDB.<br>Engine*</div></foreignObject></g></g></g><g class="node cyan" id="E1" transform="translate(288,707)" style="opacity: 1;"><rect rx="0" ry="0" x="-63.5" y="-22" width="127" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-53.5,-12)"><foreignObject width="107" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">SQLite3 engine</div></foreignObject></g></g></g><g class="node cyan" id="E2" transform="translate(625,707)" style="opacity: 1;"><rect rx="0" ry="0" x="-52.5" y="-46" width="105" height="92"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-42.5,-36)"><foreignObject width="85" height="72"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">CRUD<br>in-memory<br>TSQLRecord</div></foreignObject></g></g></g><g class="node cyan" id="E3" transform="translate(872.25,707)" style="opacity: 1;"><rect rx="0" ry="0" x="-114.5" y="-34" width="229" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-104.5,-24)"><foreignObject width="209" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLDBConnectionProperties<br>TSQLDBStatement</div></foreignObject></g></g></g><g class="node cyan" id="E4" transform="translate(1148.25,707)" style="opacity: 1;"><rect rx="0" ry="0" x="-111.5" y="-34" width="223" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-101.5,-24)"><foreignObject width="203" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Remote TSQLRestClientHTTP<br>Local TSQLRestServerDB</div></foreignObject></g></g></g><g class="node cyan" id="E5" transform="translate(1472.75,707)" style="opacity: 1;"><rect rx="0" ry="0" x="-75.5" y="-34" width="151" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-65.5,-24)"><foreignObject width="131" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TMongoCollection<br>MongoDB Client</div></foreignObject></g></g></g><g class="node cyan" id="F1" transform="translate(115.5,909)" style="opacity: 1;"><rect rx="0" ry="0" x="-60.5" y="-22" width="121" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-50.5,-12)"><foreignObject width="101" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">SQLite3 BTREE</div></foreignObject></g></g></g><g class="node cyan" id="F2" transform="translate(316.5,909)" style="opacity: 1;"><rect rx="0" ry="0" x="-90.5" y="-34" width="181" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-80.5,-24)"><foreignObject width="161" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLVirtualTableJSON<br>TSQLVirtualTableBinary</div></foreignObject></g></g></g><g class="node cyan" id="F3" transform="translate(625.5,909)" style="opacity: 1;"><rect rx="0" ry="0" x="-96.5" y="-22" width="193" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-86.5,-12)"><foreignObject width="173" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLVirtualTableExternal</div></foreignObject></g></g></g><g class="node cyan" id="F4" transform="translate(1288.25,909)" style="opacity: 1;"><rect rx="0" ry="0" x="-56.5" y="-34" width="113" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-46.5,-24)"><foreignObject width="93" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">OleDB/ODBC<br>or other</div></foreignObject></g></g></g><g class="node cyan" id="G1" transform="translate(115.5,1087)" style="opacity: 1;"><rect rx="0" ry="0" x="-55.5" y="-22" width="111" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-45.5,-12)"><foreignObject width="91" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Database file</div></foreignObject></g></g></g><g class="node cyan" id="G2" transform="translate(379.25,1087)" style="opacity: 1;"><rect rx="0" ry="0" x="-52.5" y="-46" width="105" height="92"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-42.5,-36)"><foreignObject width="85" height="72"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Process<br>in-memory<br>TSQLRecord</div></foreignObject></g></g></g><g class="node cyan" id="G3" transform="translate(625.5,1087)" style="opacity: 1;"><rect rx="0" ry="0" x="-114.5" y="-22" width="229" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-104.5,-12)"><foreignObject width="209" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLDBConnectionProperties</div></foreignObject></g></g></g><g class="node cyan" id="G4" transform="translate(1288.25,1087)" style="opacity: 1;"><rect rx="0" ry="0" x="-43" y="-34" width="86" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-33,-24)"><foreignObject width="66" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Database<br>Client</div></foreignObject></g></g></g><g class="node cyan" id="H" transform="translate(1230.25,1229)" style="opacity: 1;"><rect rx="0" ry="0" x="-74.5" y="-22" width="149" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-64.5,-12)"><foreignObject width="129" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">TSQLDBStatement</div></foreignObject></g></g></g><g class="node cyan" id="I" transform="translate(1230.25,1347)" style="opacity: 1;"><rect rx="0" ry="0" x="-87.5" y="-22" width="175" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-77.5,-12)"><foreignObject width="155" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">OleDB/ODBC or other</div></foreignObject></g></g></g><g class="node cyan" id="J" transform="translate(1230.25,1465)" style="opacity: 1;"><rect rx="0" ry="0" x="-65.5" y="-22" width="131" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-55.5,-12)"><foreignObject width="111" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Database Client</div></foreignObject></g></g></g></g></g></g></svg></div>
<p>  您可以在<a href="">数据访问基准测试</a>中找到此独特架构的一些速度测试数据。</p>
<h2 id="toc_2">12.2. 无状态设计<a class="vnote-anchor" href="#toc_2" data-anchor-icon="#"></a></h2>
<h3 id="toc_3">12.2.1. 服务端同步<a class="vnote-anchor" href="#toc_3" data-anchor-icon="#"></a></h3>
<p>  即使是无状态ORM，也始终需要在更新记录时由服务器端触发某些事件。</p>
<p>  在服务端，您可以使用如下方法原型：</p>
<pre><code class="lang-pascal hljs"><span class="hljs-keyword">type</span>
  <span class="hljs-comment">///  used to define how to trigger Events on record update</span>
  <span class="hljs-comment">// - see TSQLRestServer.OnUpdateEvent property</span>
  <span class="hljs-comment">// - returns true on success, false if an error occured (but action must continue)</span>
  TNotifySQLEvent = <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(Sender: TSQLRestServer; Event: TSQLEvent;
    aTable: TSQLRecordClass; aID: TID)</span>:</span> boolean <span class="hljs-keyword">of</span> <span class="hljs-keyword">object</span>;

  <span class="hljs-title">TSQLRestServer</span> = <span class="hljs-keyword">class</span>(TSQLRest)
 (...)
    <span class="hljs-comment">/// a method can be specified here to trigger events after any table update</span>
    OnUpdateEvent: TNotifySQLEvent;
</code></pre>
<h3 id="toc_4">12.2.2. 客户端同步<a class="vnote-anchor" href="#toc_4" data-anchor-icon="#"></a></h3>
<p>  但是，如果您希望将更新通知发送所有客户端，则没有直接的方法将这些事件从服务端广播到所有客户端。</p>
<p>  对于面向管道的传输层，如命名管道或TCP/IP-HTTP协议，技术上甚至不可行。</p>
<p>  在此情况下，您可以也只能是，在客户端应用程序中使用定时器器来调用<code>TSQLRestClientURI.UpdateFromServer()</code>方法刷新所有<code>TSQLRecord</code>或<code>TSQLTableJSON</code>实例内容：</p>
<pre><code class="lang-pascal hljs"><span class="hljs-comment">/// check if the data may have changed of the server for this objects, and</span>
<span class="hljs-comment">// update it if possible</span>
<span class="hljs-comment">// - only working types are TSQLTableJSON and TSQLRecord descendants</span>
<span class="hljs-comment">// - make use of the InternalState function to check the data content revision</span>
<span class="hljs-comment">// - return true if Data is updated successfully, or false on any error</span>
<span class="hljs-comment">// during data retrieval from server (e.g. if the TSQLRecord has been deleted)</span>
<span class="hljs-comment">// - if Data contains only one TSQLTableJSON, PCurrentRow can point to the</span>
<span class="hljs-comment">// current selected row of this table, in order to refresh its value</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UpdateFromServer</span><span class="hljs-params">(<span class="hljs-keyword">const</span> Data: <span class="hljs-keyword">array</span> <span class="hljs-keyword">of</span> TObject; <span class="hljs-keyword">out</span> Refreshed: boolean; PCurrentRow: PInteger = <span class="hljs-keyword">nil</span>)</span>:</span> boolean;
</code></pre>
<p>  使用秒计时器，即使在远程网络上也能快速响应。</p>
<p>  REST的无状态方面允许这种方法，这在设计上是安全的。</p>
<p>  通知由我们的客户端用户界面类在本地处理，使用以下参数定义用户界面：</p>
<pre><code class="lang-pascal hljs"><span class="hljs-comment">/// defines the settings for a Tab</span>
  TSQLRibbonTabParameters = <span class="hljs-keyword">object</span>
  (...)
    <span class="hljs-comment">/// by default, the screens are not refreshed automaticaly</span>
    <span class="hljs-comment">// - but you can enable the auto-refresh feature by setting this</span>
    <span class="hljs-comment">// property to TRUE, and creating a WM_TIMER timer to the form</span>
    AutoRefresh: boolean;
</code></pre>
<p>  仅当您在主应用程序窗体中处理<code>WM_TIMER</code>消息并调用<code>Ribbon.WMRefreshTimer</code>，此参数才有效。</p>
<p>  例如，在主演示（<code>FileMain.pas</code>单元）中查看此方法：</p>
<pre><code class="lang-pascal hljs"><span class="hljs-function"><span class="hljs-keyword">procedure</span> <span class="hljs-title">TMainForm</span>.<span class="hljs-title">WMRefreshTimer</span><span class="hljs-params">(<span class="hljs-keyword">var</span> Msg: TWMTimer)</span>;</span>
<span class="hljs-keyword">begin</span>
  Ribbon.WMRefreshTimer(Msg);
<span class="hljs-keyword">end</span>;
</code></pre>
<p>  在多线程客户端应用程序中，甚至在服务端，无状态方法使编写软件更容易。您不必关心在客户端屏幕中强制数据刷新。这取决于屏幕是否刷新。在实践中，我发现依靠计时器非常有效，而不是调用所谓“精致”的<code>TThread. Synchronize</code>方法。</p>
<h3 id="toc_5">12.2.3. 应用程序响应<a class="vnote-anchor" href="#toc_5" data-anchor-icon="#"></a></h3>
<p>  默认情况下，在当前线程中执行所有客户端通信，如典型的GUI应用是在<code>main</code>线程。</p>
<p>  由于所有通信都是在阻塞模式下执行的，如果远程请求需要很长时间来处理（由于网络错误、慢速或服务端长时间操作），最终用户体验可能会出现应用程序无响应，即使Windows会提示“无响应的应用程序”，并且可能会建议终止这个远离预期行为的进程。</p>
<p>  为了与用户正确交互，在<code>TSQLRestClientURI</code>中定义了<code>OnIdle</code>属性，并更改了通信的处理方式。如果定义了回调事件，则所有客户端通信都将在后台线程中处理，并且当前线程（多半是main UI线程）将等待后台执行请求，同时在循环中运行<code>OnIdle</code>回调。</p>
<p>  您可以在<code>mORMotUILogin</code>单元中找到与此回调签名匹配的两种方法：</p>
<pre><code class="lang-pascal hljs">  <span class="hljs-title">TLoginForm</span> = <span class="hljs-keyword">class</span>(TForm)
  (...)
    <span class="hljs-keyword">class</span> <span class="hljs-function"><span class="hljs-keyword">procedure</span> <span class="hljs-title">OnIdleProcess</span><span class="hljs-params">(Sender: TSynBackgroundThreadAbstract; ElapsedMS: Integer)</span>;</span>
    <span class="hljs-keyword">class</span> <span class="hljs-function"><span class="hljs-keyword">procedure</span> <span class="hljs-title">OnIdleProcessForm</span><span class="hljs-params">(Sender: TSynBackgroundThreadAbstract; ElapsedMS: Integer)</span>;</span>
  <span class="hljs-keyword">end</span>;
</code></pre>
<p>  第一个<code>OnIdleProcess()</code>回调将在定义的时间周期后将鼠标光标形状更改为<code>crHourClass</code>。 如果请求需要很多时间，<code>OnIdleProcessForm()</code>回调不仅会更改鼠标光标，还会显示一个带有*'Please wait...'* 消息的弹出窗口。 两者都将调用<code>Application.ProcessMessages</code>以保持应用程序用户界面的响应。</p>
<p>  还定义了一些全局变量来调整这两个回调的行为：</p>
<pre><code class="lang-pascal hljs"><span class="hljs-keyword">var</span>
  <span class="hljs-comment">/// define when TLoginForm.OnIdleProcess() has to display the crHourGlass cursor</span>
  <span class="hljs-comment">// after a given time elapsed, in milliseconds</span>
  <span class="hljs-comment">// - default is 100 ms</span>
  OnIdleProcessCursorChangeTimeout: integer = <span class="hljs-number">100</span>;

  <span class="hljs-comment">/// define when TLoginForm.OnIdleProcessForm() has to display the temporary</span>
  <span class="hljs-comment">// form after a given time elapsed, in milliseconds</span>
  <span class="hljs-comment">// - default is 2000 ms, i.e. 2 seconds</span>
  OnIdleProcessTemporaryFormTimeout: integer = <span class="hljs-number">2000</span>;

  <span class="hljs-comment">/// define the message text displayed by TLoginForm.OnIdleProcessForm()</span>
  <span class="hljs-comment">// - default is sOnIdleProcessFormMessage resourcestring, i.e. 'Please wait...'</span>
  OnIdleProcessTemporaryFormMessage: <span class="hljs-keyword">string</span>;
</code></pre>
<p>  因此，您可以更改这些设置以自定义用户体验。我们针对每个请求使用3秒的计时器对其进行了测试，应用程序运行平稳，即使速度很慢也与大多数Web应用程序相当。 main demo的SynFile（在<code>SQlite3\Samples\MainDemo</code>文件夹中）定义了这样的回调。</p>
<p>  请注意，此<code>OnIdle</code>功能是在<code>TSQLRestClientURI</code>类级别定义的，因此可用于所有通信协议，不仅HTTP也包括命名管道或进程内，因此可用于在一些耗时的进程中增强用户体验。</p>
<h2 id="toc_6">12.3. 通过批次序列添加/更新/删除记录<a class="vnote-anchor" href="#toc_6" data-anchor-icon="#"></a></h2>
<h3 id="toc_7">12.3.1. 批次处理过程<a class="vnote-anchor" href="#toc_7" data-anchor-icon="#"></a></h3>
<p>  何时使用所谓的批次序列？</p>
<p>  在标准的客户端-服务端架构中，特别是对大家都理解的RESTful服务（和大多数实现），任何<code>Add / Update / Delete</code>方法调用都需与远程服务器进行交互，发生所谓的往返：将消息发送到客户端，将响应发送回客户端。</p>
<p>  如果通过Internet（或慢速网络）进行远程连接，您可能会有长达100毫秒的延迟，这还只是“ping”的时间，即IP数据包到达服务器并返回所花费的时间。</p>
<p>  如果您正在进行大量此类调用（如添加1000条记录），那么仅仅因为网络延迟，您将需要100 * 1000 ms = 100 s = 1:40 min！</p>
<div class="mermaid-diagram"><svg id="mermaid-diagram-6" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 236.25 530" style="max-width:236.25px;"><style type="text/css" title="mermaid-svg-internal-css">/*  */
#mermaid-diagram-6 .node&gt;rect { ; }
#mermaid-diagram-6 .node text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-6 .edgeLabel text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-6 .cluster rect  { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-6 .cyan&gt;rect, .cyan&gt;polygon, .cyan&gt;circle, .cyan&gt;ellipse { fill:#9ff;  stroke:#fff; }
/*  */
</style><g><g class="output"><g class="clusters"></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M99.99647887323944,64L80.5,113L99.99647887323944,162" marker-end="url(#arrowhead707)" style="fill:none"></path><defs><marker id="arrowhead707" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M97.51760563380282,206L72.5,255L97.51760563380282,304" marker-end="url(#arrowhead708)" style="fill:none"></path><defs><marker id="arrowhead708" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M99.99647887323944,348L80.5,397L99.99647887323944,446" marker-end="url(#arrowhead709)" style="fill:none"></path><defs><marker id="arrowhead709" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M117.50352112676056,446L137,397L117.50352112676056,348" marker-end="url(#arrowhead710)" style="fill:none"></path><defs><marker id="arrowhead710" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M119.98239436619718,304L145,255L119.98239436619718,206" marker-end="url(#arrowhead711)" style="fill:none"></path><defs><marker id="arrowhead711" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M117.50352112676056,162L137,113L117.50352112676056,64" marker-end="url(#arrowhead712)" style="fill:none"></path><defs><marker id="arrowhead712" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(80.5,113)" style="opacity: 1;"><g transform="translate(-36.5,-24)" class="label"><foreignObject width="73" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">In-process<br>no latency</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(72.5,255)" style="opacity: 1;"><g transform="translate(-52.5,-24)" class="label"><foreignObject width="105" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">Internet<br>100 ms latency</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(80.5,397)" style="opacity: 1;"><g transform="translate(-36.5,-24)" class="label"><foreignObject width="73" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">In-process<br>no latency</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node cyan" id="A" transform="translate(108.75,42)" style="opacity: 1;"><rect rx="0" ry="0" x="-87.5" y="-22" width="175" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-77.5,-12)"><foreignObject width="155" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">ORM CRUD operation</div></foreignObject></g></g></g><g class="node cyan" id="B" transform="translate(108.75,184)" style="opacity: 1;"><rect rx="0" ry="0" x="-71.5" y="-22" width="143" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-61.5,-12)"><foreignObject width="123" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">ORM HTTP Client</div></foreignObject></g></g></g><g class="node cyan" id="C" transform="translate(108.75,326)" style="opacity: 1;"><rect rx="0" ry="0" x="-73" y="-22" width="146" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-63,-12)"><foreignObject width="126" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">ORM HTTP Server</div></foreignObject></g></g></g><g class="node cyan" id="D" transform="translate(108.75,468)" style="opacity: 1;"><rect rx="0" ry="0" x="-79.5" y="-22" width="159" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-69.5,-12)"><foreignObject width="139" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">ORM database core</div></foreignObject></g></g></g></g></g></g></svg></div>
<p>  批次序列允许您将这些语句重新组合成一个远程调用。在内部，它构建一个JSON流，然后立即将此流发布到服务器，服务器在执行了所有修改后立即回应。</p>
<p>  添加了一些新的<code>TSQLRestClientURI</code>方法来实现批次序列以加速数据库修改：在调用<code>BatchStart</code>之后，通过<code>BatchAdd / BatchUpdate / BatchDelete</code>将数据库修改语句添加到序列中，然后通过<code>BatchSend</code>将所有语句作为一条语句发送到远程服务器，在远程连接速度较慢（通常是Internet上的HTTP）的情况下，这比单独调用<code>Add / Update / Delete</code>要快得多。</p>
<p>  由于语句是一次执行的，因此在将请求附加到批次序列的时，您无法获取结果（如添加的行的ID）。因此，您必须等待<code>BatchSend</code>方法一次性获取所有结果，结果为<code>array of TID</code>动态数组。</p>
<p>  正如您可能猜到的，在整个过程中使用事务也是一个好主意。默认情况下，BATCH序列未嵌入到事务中。</p>
<p>  您有两种可能性来添加交易：</p>
<ul>
<li>
<p>让调用者使用显式的<code>TransactionBegin</code> ... <code>try</code>... <code>Commit except RollBack</code>语句块；</p>
</li>
<li>
<p>或者在<code>BatchStart()</code>中对一些行指定<code>AutomaticTransactionPerRow</code>参数：在这种情况下，将在服务器端触发一个事务（最多到指定的行数）。如果要在单个事务中修改所有行，则可以设置<code>maxInt</code>。</p>
</li>
</ul>
<p>  第二种方法是首选方法，因为从客户端定义事务并不是一个好主意：它可能阻止其他客户端尝试创建自己的事务。</p>
<p>  这是摘自SynSelfTests.pas回归测试中的典型用法：</p>
<pre><code class="lang-pascal hljs">  <span class="hljs-comment">// start the BATCH sequence</span>
  Check(ClientDist.BatchStart(TSQLRecordPeople,<span class="hljs-number">1000</span>));
  <span class="hljs-comment">// now a transaction will be created by chunk of 1000 modifications</span>
  <span class="hljs-comment">// delete some elements</span>
  <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span> <span class="hljs-keyword">to</span> n-<span class="hljs-number">1</span> <span class="hljs-keyword">do</span>
    Check(ClientDist.BatchDelete(IntArray[i])=i);
  <span class="hljs-comment">// update some elements</span>
  nupd := <span class="hljs-number">0</span>;
  <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span> <span class="hljs-keyword">to</span> aStatic.Count-<span class="hljs-number">1</span> <span class="hljs-keyword">do</span>
  <span class="hljs-keyword">if</span> i <span class="hljs-keyword">and</span> <span class="hljs-number">7</span>&lt;&gt;<span class="hljs-number">0</span> <span class="hljs-keyword">then</span>
  <span class="hljs-keyword">begin</span> <span class="hljs-comment">// not yet deleted in BATCH mode</span>
    Check(ClientDist.Retrieve(aStatic.ID[i],V));
    V.YearOfBirth := <span class="hljs-number">1800</span>+nupd;
    Check(ClientDist.BatchUpdate(V)=nupd+n);
    inc(nupd);
  <span class="hljs-keyword">end</span>;
  <span class="hljs-comment">// add some elements</span>
  V.LastName := <span class="hljs-string">'New'</span>;
  <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span> <span class="hljs-keyword">to</span> <span class="hljs-number">1000</span> <span class="hljs-keyword">do</span>
  <span class="hljs-keyword">begin</span>
    V.FirstName := RandomUTF8(<span class="hljs-number">10</span>);
    V.YearOfBirth := i+<span class="hljs-number">1000</span>;
    Check(ClientDist.BatchAdd(V,true)=n+nupd+i);
  <span class="hljs-keyword">end</span>;
  <span class="hljs-comment">// send the BATCH sequences to the server</span>
  Check(ClientDist.BatchSend(Results)=<span class="hljs-number">200</span>);
  <span class="hljs-comment">// now all data has been commited on the server</span>
  <span class="hljs-comment">// now Results[] contains the results of every BATCH statement...</span>
  Check(Length(Results)=n+nupd+<span class="hljs-number">1001</span>);
  <span class="hljs-comment">// Results[0] to Results[n-1] should be 200 = deletion OK</span>
  <span class="hljs-comment">// Results[n] to Results[n+nupd-1] should be 200 = update OK</span>
  <span class="hljs-comment">// Results[n+nupd] to Results[high(Results)] are the IDs of each added record</span>
  <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span> <span class="hljs-keyword">to</span> high(Results) <span class="hljs-keyword">do</span>
    <span class="hljs-keyword">if</span> i&lt;nupd+n <span class="hljs-keyword">then</span>
      Check(Results[i]=<span class="hljs-number">200</span>) <span class="hljs-keyword">else</span>
    <span class="hljs-keyword">begin</span>
      Check(Results[i]&gt;<span class="hljs-number">0</span>);
      ndx := aStatic.IDToIndex(Results[i]);
      Check(ndx&gt;=<span class="hljs-number">0</span>);
      <span class="hljs-keyword">with</span> TSQLRecordPeople(aStatic.Items[ndx]) <span class="hljs-keyword">do</span>
      <span class="hljs-keyword">begin</span>
        Check(LastName=<span class="hljs-string">'New'</span>,<span class="hljs-string">'BatchAdd'</span>);
        Check(YearOfBirth=<span class="hljs-number">1000</span>+i-nupd-n);
      <span class="hljs-keyword">end</span>;
    <span class="hljs-keyword">end</span>;
  <span class="hljs-comment">// check ClientDist.BatchDelete(IntArray[i]) did erase the record</span>
  <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span> <span class="hljs-keyword">to</span> n-<span class="hljs-number">1</span> <span class="hljs-keyword">do</span>
    Check(<span class="hljs-keyword">not</span> ClientDist.Retrieve(IntArray[i],V),<span class="hljs-string">'BatchDelete'</span>);
</code></pre>
<p>  在上面的代码中，所有CRUD操作都照常执行，使用<code>BatchAdd BatchDelete BatchUpdate</code>方法而不是普通的<code>Add Delete Update</code>方法。 ORM将负责所有底层数据处理，包括JSON序列化，自动创建事务块和生成SQL语句，并进行了多项优化。</p>
<p>  在上面的示例中，我们启动了仅涉及TSQLRecordPeople类对象的批处理：</p>
<pre><code class="lang-pascal hljs">  Check(ClientDist.BatchStart(TSQLRecordPeople,<span class="hljs-number">1000</span>));
</code></pre>
<p>  但是，如果将类设置为nil，则可以混合任何类型的TSQLRecord内容，如下所示：</p>
<pre><code class="lang-pascal hljs">  Check(ClientDist.BatchStart(<span class="hljs-keyword">nil</span>,<span class="hljs-number">1000</span>));
</code></pre>
<p>  或使用<code>BatchStartAny()</code>方法：</p>
<pre><code class="lang-pascal hljs">  Check(ClientDist.BatchStartAny(<span class="hljs-number">1000</span>));
</code></pre>
<p>  实际上，您应该更好地创建和维护自己的<code>TSQLRestBatch</code>实例，这样您就可以实现任意数量的并发批次处理 - 见下文。</p>
<h3 id="toc_8">12.3.2. JSON传输<a class="vnote-anchor" href="#toc_8" data-anchor-icon="#"></a></h3>
<p>  如上所述，所有<code>Batch*()</code>方法都在客户端将对象值序列化为JSON，然后将此JSON发送到服务器，这样处理就不需要任何客户端-服务端往返和缓慢延迟。</p>
<p>  以下是发送到服务器的典型JSON流的一些摘录：</p>
<pre><code class="lang-json hljs">{<span class="hljs-attr">"People"</span>:[<span class="hljs-string">"DELETE"</span>,<span class="hljs-number">2</span>,<span class="hljs-string">"DELETE"</span>,<span class="hljs-number">13</span>,<span class="hljs-string">"DELETE"</span>,<span class="hljs-number">24</span>,
   (...)  all DELETE actions
  ,<span class="hljs-string">"DELETE"</span>,<span class="hljs-number">11010</span>,
  <span class="hljs-string">"PUT"</span>,{<span class="hljs-attr">"RowID"</span>:<span class="hljs-number">3</span>,<span class="hljs-attr">"FirstName"</span>:<span class="hljs-string">"Sergei1"</span>,<span class="hljs-attr">"LastName"</span>:<span class="hljs-string">"Rachmaninoff"</span>,<span class="hljs-attr">"YearOfBirth"</span>:<span class="hljs-number">1800</span>, <span class="hljs-attr">"YearOfDeath"</span>:<span class="hljs-number">1943</span>},
  <span class="hljs-string">"PUT"</span>,{<span class="hljs-attr">"RowID"</span>:<span class="hljs-number">4</span>,<span class="hljs-attr">"FirstName"</span>:<span class="hljs-string">"Alexandre1"</span>,<span class="hljs-attr">"LastName"</span>:<span class="hljs-string">"Dumas"</span>,<span class="hljs-attr">"YearOfBirth"</span>:<span class="hljs-number">1801</span>, <span class="hljs-attr">"YearOfDeath"</span>:<span class="hljs-number">1870</span>},
   (...)  all PUT = update actions
  <span class="hljs-string">"PUT"</span>,{<span class="hljs-attr">"RowID"</span>:<span class="hljs-number">11012</span>,<span class="hljs-attr">"FirstName"</span>:<span class="hljs-string">"Leonard"</span>,<span class="hljs-attr">"LastName"</span>:<span class="hljs-string">"da VinÃ§i"</span>,<span class="hljs-attr">"YearOfBirth"</span>:<span class="hljs-number">9025</span>, <span class="hljs-attr">"YearOfDeath"</span>:<span class="hljs-number">1519</span>},
  <span class="hljs-string">"POST"</span>,{<span class="hljs-attr">"FirstName"</span>:<span class="hljs-string">"â@â¢Å"</span>Hâ mÂ£Â g<span class="hljs-string">","</span>LastName<span class="hljs-string">":"</span>New<span class="hljs-string">","</span>YearOfBirth<span class="hljs-string">":1000, "</span>YearOfDeath<span class="hljs-string">":1519},
  "</span>POST<span class="hljs-string">",{"</span>FirstName<span class="hljs-string">":"</span>@â¦,KAÂ½Ã #Â¶f<span class="hljs-attr">","</span>LastName<span class="hljs-attr">":"</span>New<span class="hljs-attr">","</span>YearOfBirth<span class="hljs-attr">":1001, "</span>YearOfDeath<span class="hljs-attr">":1519},
   (...)  all POST = add actions
 "</span>POST<span class="hljs-attr">",{"</span>FirstName<span class="hljs-attr">":"</span>+ÂtqCXW3Ã\<span class="hljs-attr">""</span>,<span class="hljs-attr">"LastName"</span>:<span class="hljs-string">"New"</span>,<span class="hljs-attr">"YearOfBirth"</span>:<span class="hljs-number">2000</span>, <span class="hljs-attr">"YearOfDeath"</span>:<span class="hljs-number">1519</span>}
  ]}
</code></pre>
<p>  如果<code>BatchAdd</code>仅包含简单字段（这是默认），则不会传输这些字段名称，并且将在JSON流中发送以下内容，以减少带宽使用：</p>
<pre><code class="lang-json hljs">  <span class="hljs-string">"SIMPLE"</span>,[<span class="hljs-string">"â@â¢Å"</span>Hâ mÂ£Â g<span class="hljs-string">","</span>New<span class="hljs-string">",1000,1519],
</span></code></pre>
<p>  默认情况下，批次处理内容中不包括BLOB字段：仅发送简单字段。 但<code>BatchAdd BatchUpdate</code>方法（或相应的TSQLRestBatch <code>Add</code>或<code>Update</code>方法）可能包含要传输的自定义字段列表，您可以在其中指定任何TSQLRawBlob字段：二进制BLOB内容将在JSON过程中编码为Base64，您可以在这种情况下，最终平衡一些资源和速度。 当然，所有数据都应该足够小，以便存储在内存中，因此BLOB字段上限应该最多到几十MB，如果你有大量的数据，那么可在循环中使用几个Batch实例。</p>
<p>  成功时，将从服务器接收以下JSON流：</p>
<pre><code class="lang-json hljs"> [<span class="hljs-number">200</span>,<span class="hljs-number">200</span>,...]
</code></pre>
<p>  此结果数组是HTTP状态代码（此处200表示正常）或新添加的ID（对于<code>BatchAdd</code>命令）。</p>
<p>  所有JSON编码（客户端）和解析（服务端）都已经过优化，可以最大限度地减少所需的资源。使用新的内部SynLZ压缩（默认情况下在我们的HTTP客户端-服务端类中可用），可进一步降低带宽使用。</p>
<p>  由于这个批次过程，现在大部分时间都花在了数据库引擎本身，而不在通信层中。</p>
<h3 id="toc_9">12.3.3. 单元工作模式<a class="vnote-anchor" href="#toc_9" data-anchor-icon="#"></a></h3>
<h4 id="toc_10">12.3.3.1. 几个批次<a class="vnote-anchor" href="#toc_10" data-anchor-icon="#"></a></h4>
<p>  在<code>TSQLRestClientUR</code>I端，所有<code>BatchStart / BatchAdd / BatchUpdate / BatchDelete</code>方法在批次准备期间使用单个临时存储。仅有一个线程访问方法时，这可能是安全的，但这通常是REST客户端应用程序的情况。</p>
<p>  实际上，所有批次进程都使用<code>TSQLRestBatch</code>类，它可以动态创建，并安全地共存为同一个<code>TSQLRest</code>的多个实例，因此，您可以创建自己的本地<code>TSQLRestBatch</code>实例，以实现安全的批次处理。事实上，而在<code>TSQLRestServer</code>端则是必需的，它没有<code>Batch*()</code>方法，因为它们不是线程安全的。</p>
<p>  在服务端，您可以这样编写：</p>
<pre><code class="lang-pascal hljs"><span class="hljs-keyword">var</span> Batch: TSQLRestBatch;
    IDs: TIntegerDynArray;
...
  Batch := TSQLRestBatch.Create(Server,TSQLRecordTest,<span class="hljs-number">30</span>);
  <span class="hljs-keyword">try</span>
    <span class="hljs-keyword">for</span> i := <span class="hljs-number">10000</span> <span class="hljs-keyword">to</span> <span class="hljs-number">10099</span> <span class="hljs-keyword">do</span> <span class="hljs-keyword">begin</span>
      R.Int := i;
      R.Test := Int32ToUTF8(i);
      Check(Batch.Add(R,true)=i-<span class="hljs-number">10000</span>);
    <span class="hljs-keyword">end</span>;
    Check(Server.BatchSend(Batch,IDs)=HTTP_SUCCESS);
  <span class="hljs-keyword">finally</span>
    Batch.Free;
  <span class="hljs-keyword">end</span>;
</code></pre>
<p>  同时处理多个<code>TSQLRestBatch</code>类的能力将允许实现工作单元模式。它可用于维护受业务事务影响的对象列表，并协调写入变更和并发问题的解决方案，尤其是在具有大量连接客户端的复杂SOA应用程序中。</p>
<p>  在某种程度上，您可以将工作单元视为转储所有事务处理代码的位置。</p>
<p>  工作单元的职责是：</p>
<ul>
<li>管理交易；</li>
<li>处理数据库插入、删除和更新；</li>
<li>防止并发问题；</li>
<li>分组请求以最大化数据库性能。</li>
</ul>
<p>  使用工作单元模式的价值在于将其余代码从这些问题中解放出来，这样您就可以专注于业务逻辑。</p>
<h4 id="toc_11">12.3.3.2. 仅更新映射字段<a class="vnote-anchor" href="#toc_11" data-anchor-icon="#"></a></h4>
<p>  实际上，如果在执行了<code>FillPrepare</code>的记录上调用而未取消映射（即未调用<code>FillClose</code>），<code>BatchUpdate</code>方法将仅更新映射的字段，这是检索/修改过程的一致性所必需的。</p>
<p>  例如，在以下代码中，<code>V.FillPrepare</code>将仅检索<code>TSQLRecordPeople</code>表的<code>ID</code>和<code>YearOfBirth</code>字段，因此后续<code>BatchUpdate(V)</code>调用将仅更新<code>YearOfBirth</code>字段：</p>
<pre><code class="lang-pascal hljs">  <span class="hljs-comment">// test BATCH update from partial FillPrepare</span>
  V.FillPrepare(ClientDist,<span class="hljs-string">'LastName=:("New"):'</span>,<span class="hljs-string">'ID,YearOfBirth'</span>);
  <span class="hljs-keyword">if</span> ClientDist.TransactionBegin(TSQLRecordPeople) <span class="hljs-keyword">then</span>
  <span class="hljs-keyword">try</span>
    Check(ClientDist.BatchStart(TSQLRecordPeople));
    n := <span class="hljs-number">0</span>;
    V.LastName := <span class="hljs-string">'NotTransmitted'</span>;
    <span class="hljs-keyword">while</span> V.FillOne <span class="hljs-keyword">do</span> <span class="hljs-keyword">begin</span>
      Check(V.LastName=<span class="hljs-string">'NotTransmitted'</span>);
      Check(V.YearOfBirth=n+<span class="hljs-number">1000</span>);
      V.YearOfBirth := n;
      ClientDist.BatchUpdate(V); <span class="hljs-comment">// will update only V.YearOfBirth</span>
      inc(n);
    <span class="hljs-keyword">end</span>;
  (...)
</code></pre>
<p>  客户端计算并发送的JSON如下：</p>
<pre><code class="lang-json hljs">  ....,<span class="hljs-string">"PUT"</span>,{<span class="hljs-attr">"RowID"</span>:<span class="hljs-number">324</span>,<span class="hljs-attr">"YearOfBirth"</span>:<span class="hljs-number">1000</span>},...
</code></pre>
<p>  在服务端生成的SQL将是：</p>
<pre><code class="lang-sql hljs"> <span class="hljs-keyword">UPDATE</span> People <span class="hljs-keyword">SET</span> YearOfBirth=? <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">RowID</span>=?
 ... <span class="hljs-keyword">with</span> <span class="hljs-keyword">bound</span> <span class="hljs-keyword">parameters</span>: [<span class="hljs-number">1000</span>,<span class="hljs-number">324</span>]
</code></pre>
<p>  因此，批次处理可视为实现业务层工作单元的好方法。</p>
<p>  您可以使用高级OOP方法按要求修改所有对象，然后调用<code>BatchSend()</code>时一次性传输和处理所有数据。 <code>BatchStart</code> - <code>BatchSend</code> - <code>BatchAbort</code>命令将引发事务模型的安全问题，依靠客户端跟踪对象修改，并将服务器端的任何SQL或NoSQL数据库进程优化为简单的"save and forget"任务。</p>
<p>  请注意，如果在同一个<code>FillPrepare()</code>上下文中执行多个<code>ClientDist.BatchUpdate(V)</code>命令，它们将包含相同的字段（RowID和YearOfBirth）。因此，它们将生成相同的语句（<code>UPDATE People SET YearOfBirth =？WHERE RowID =？</code>），这将有益于数据库端的数组绑定。</p>
<p>  下面是一些代码，摘自“web blog”示例“30-MVC Server”，它将更新映射到表中的整数数组。所有<code>TSQLTag.Occurence</code>整数都存储在本地<code>TSQLTags.Lookup[].Occurence</code>动态数组中，该数组将用于显示文章的每个标记出现的次数。</p>
<p>  以下方法将首先从数据库中检索<code>ID</code>和<code>Occurence</code>，如果内部动态数组包含新值，则更新<code>TSQLTag.Occurence</code>。</p>
<pre><code class="lang-pascal hljs"><span class="hljs-function"><span class="hljs-keyword">procedure</span> <span class="hljs-title">TSQLTags</span>.<span class="hljs-title">SaveOccurence</span><span class="hljs-params">(aRest: TSQLRest)</span>;</span>
<span class="hljs-keyword">var</span> tag: TSQLTag;
    batch: TSQLRestBatch;
<span class="hljs-keyword">begin</span>
  Lock.ProtectMethod;
  TAutoFree.Several([
    @tag,TSQLTag.CreateAndFillPrepare(aRest,<span class="hljs-string">''</span>,<span class="hljs-string">'RowID,Occurence'</span>),
    @batch,TSQLRestBatch.Create(aRest,TSQLTag,<span class="hljs-number">1000</span>)]);
  <span class="hljs-keyword">while</span> tag.FillOne <span class="hljs-keyword">do</span> <span class="hljs-keyword">begin</span>
    <span class="hljs-keyword">if</span> tag.ID&lt;=length(Lookup) <span class="hljs-keyword">then</span>
      <span class="hljs-keyword">if</span> Lookup[tag.ID-<span class="hljs-number">1</span>].Occurence&lt;&gt;tag.Occurence <span class="hljs-keyword">then</span> <span class="hljs-keyword">begin</span>
        tag.Occurence := Lookup[tag.ID-<span class="hljs-number">1</span>].Occurence;
        batch.Update(tag); <span class="hljs-comment">// will update only Occurence field</span>
      <span class="hljs-keyword">end</span>;
  <span class="hljs-keyword">end</span>;
  aRest.BatchSend(batch);
<span class="hljs-keyword">end</span>;
</code></pre>
<p>  在上面的代码中，您可以确认：</p>
<ul>
<li><code>CreateAndFillPrepare</code> + <code>FillOne</code>方法能够检索<code>TSQLTag</code>类的所有值，并轻松迭代它们；</li>
<li>准备一个本地<code>TSQLRestBatch</code>，并通过<code>batch.Update()</code>在本地存储所有变更；正如我们已经说过的那样，只有被检索的字段（即<code>'Occurence'</code>）才会被标记为要更新；</li>
<li><code>aRest.BatchSend(batch</code>将所有新值（如果有的话）发送到服务端，仅需要单次网络往返和单个事务；</li>
<li>通过使用<code>Lock.ProtectMethod</code>方法实现线程安全（<code>Lock</code>是<code>TSQLTags</code>实例的专用互斥锁）；</li>
<li>使用<code>TAutoFree.Several()</code>，当方法退出时，将自动释放并重新分配局部变量 （请参阅<a href="">TSQLRecord自动内存处理</a>），这样可以避免编写两级嵌套的<code>try .. finally Free end</code>循环。</li>
</ul>
<p>  这种模式在mORMot中非常常见，也说明了如何使用高级ORM方法代替手工SQL处理，具有更好的性能和更清晰的代码优势。</p>
<h3 id="toc_12">12.3.4. 本地网络瓶颈<a class="vnote-anchor" href="#toc_12" data-anchor-icon="#"></a></h3>
<p>  在物理网络上使用远程数据库时，每次请求都会发生往返延迟，时间消耗在ORM服务端和外部数据库引擎之间。</p>
<div class="mermaid-diagram"><svg id="mermaid-diagram-7" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 236.25 672" style="max-width:236.25px;"><style type="text/css" title="mermaid-svg-internal-css">/*  */
#mermaid-diagram-7 .node&gt;rect { ; }
#mermaid-diagram-7 .node text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-7 .edgeLabel text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-7 .cluster rect  { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-7 .cyan&gt;rect, .cyan&gt;polygon, .cyan&gt;circle, .cyan&gt;ellipse { fill:#9ff;  stroke:#fff; }
/*  */
</style><g><g class="output"><g class="clusters"></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M99.99647887323944,64L80.5,113L99.99647887323944,162" marker-end="url(#arrowhead746)" style="fill:none"></path><defs><marker id="arrowhead746" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M97.51760563380282,206L72.5,255L97.51760563380282,304" marker-end="url(#arrowhead747)" style="fill:none"></path><defs><marker id="arrowhead747" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M99.99647887323944,348L80.5,397L99.99647887323944,446" marker-end="url(#arrowhead748)" style="fill:none"></path><defs><marker id="arrowhead748" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M97.8274647887324,490L73.5,539L97.8274647887324,588" marker-end="url(#arrowhead749)" style="fill:none"></path><defs><marker id="arrowhead749" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M119.6725352112676,588L144,539L119.6725352112676,490" marker-end="url(#arrowhead750)" style="fill:none"></path><defs><marker id="arrowhead750" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M117.50352112676056,446L137,397L117.50352112676056,348" marker-end="url(#arrowhead751)" style="fill:none"></path><defs><marker id="arrowhead751" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M119.98239436619718,304L145,255L119.98239436619718,206" marker-end="url(#arrowhead752)" style="fill:none"></path><defs><marker id="arrowhead752" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M117.50352112676056,162L137,113L117.50352112676056,64" marker-end="url(#arrowhead753)" style="fill:none"></path><defs><marker id="arrowhead753" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(80.5,113)" style="opacity: 1;"><g transform="translate(-36.5,-24)" class="label"><foreignObject width="73" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">In-process<br>no latency</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(72.5,255)" style="opacity: 1;"><g transform="translate(-52.5,-24)" class="label"><foreignObject width="105" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">Internet<br>100 ms latency</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(80.5,397)" style="opacity: 1;"><g transform="translate(-36.5,-24)" class="label"><foreignObject width="73" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">In-process<br>no latency</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(73.5,539)" style="opacity: 1;"><g transform="translate(-50.5,-24)" class="label"><foreignObject width="101" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">Local Network<br>1 ms latency</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node cyan" id="A" transform="translate(108.75,42)" style="opacity: 1;"><rect rx="0" ry="0" x="-87.5" y="-22" width="175" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-77.5,-12)"><foreignObject width="155" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">ORM CRUD operation</div></foreignObject></g></g></g><g class="node cyan" id="B" transform="translate(108.75,184)" style="opacity: 1;"><rect rx="0" ry="0" x="-71.5" y="-22" width="143" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-61.5,-12)"><foreignObject width="123" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">ORM HTTP Client</div></foreignObject></g></g></g><g class="node cyan" id="C" transform="translate(108.75,326)" style="opacity: 1;"><rect rx="0" ry="0" x="-73" y="-22" width="146" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-63,-12)"><foreignObject width="126" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">ORM HTTP Server</div></foreignObject></g></g></g><g class="node cyan" id="D" transform="translate(108.75,468)" style="opacity: 1;"><rect rx="0" ry="0" x="-79.5" y="-22" width="159" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-69.5,-12)"><foreignObject width="139" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">ORM database core</div></foreignObject></g></g></g><g class="node cyan" id="E" transform="translate(108.75,610)" style="opacity: 1;"><rect rx="0" ry="0" x="-50.5" y="-22" width="101" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-40.5,-12)"><foreignObject width="81" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">External DB</div></foreignObject></g></g></g></g></g></g></svg></div>
<p>  首先，由于外部数据库往返而导致的1ms延迟似乎可以忽略不计。用于添加/更新/删除记录的批次序列确实已经缩短了因特网延迟，这种情况已经大大缩小了延迟。</p>
<p>  但是在面向服务的架构（SOA）中，大多数进程都是在服务器端完成的，即便是最轻微的执行延迟也会导致明显的性能损失。实际上，在任何SQL数据库上执行单独的<code>INSERT</code>、<code>DELETE</code>或<code>UPDATE</code>语句时，您将无法实现每秒超过500-600个请求。即使在同一服务器上本地运行，大多数SQL数据库也会受到进程间通信的开销的影响，最多只能达到每秒6,000-7,000次更新请求。</p>
<p>  您的客户可能不明白为什么使用SQLite3引擎会比他们支付巨额资金的专用Oracle实例快得多，因为SQLite3运行在ORM服务进程中。一种常见的解决方案是使用存储过程，或者为您的数据库优化SQL，但是您将失去很多ORM和SOA的好处 。</p>
<p>  当然，mORMot可以做得更好。它的ORM会自动使用两种方法来减少数据库的往返次数：</p>
<ul>
<li>使用数组绑定；</li>
<li>或多条INSERT语句 。</li>
</ul>
<p>  两种方法都将尽可能地将所有传输的数据分组。因此，性能将提高，达到每秒50,000-60,000次写入，具体取决于数据库的能力。</p>
<p>  默认情况下启用这些功能，ORM核心始终会选择最快的方法，只要它在数据库后端可用即可，您不必担心应用程序配置，享速度即可。</p>
<h4 id="toc_13">12.3.4.1. 数组绑定<a class="vnote-anchor" href="#toc_13" data-anchor-icon="#"></a></h4>
<h5 id="toc_14">12.3.4.1.1. 更快的批次模式<a class="vnote-anchor" href="#toc_14" data-anchor-icon="#"></a></h5>
<p>  当与外部SQL数据库访问结合使用时，如果相应的·TSQLDBConnection·类支持该功能，则批次方法可以实现为数组绑定。到目前为止，只有<code>SynDBOracle</code>、<code>SynDBZeos</code>和<code>SynDBFireDAC</code>单元实现了。</p>
<p>  我们的<code>SynDB.pas</code>单元提供了一些<code>TSQLDBStatement.BindArray()</code>方法，引入了本地数组绑定，以便更快地批量修改数据库。它与ORM的批次方法结合使用，因此CRUD修改操作将组包成网络上的单次往返。</p>
<p>  由于这种增强功能，根据我们的数据访问基准测试，在Oracle（通过100 Mb以太网）中插入记录的速度从每秒400-500行提升到超过每秒70,000行。</p>
<p>  ZEOS开源库的优秀维护者特别优化其内部结构以全速支持mORMot，直接访问ZDBC层。 ZEOS 7.2分支确实受益于巨大的代码重构，并且还引入了数组绑定功能。如果ZDBC驱动侧支持，我们的ORM将识别和处理此功能。今天，只有ZDBC Oracle和Firebird驱动支持此功能，但名单还在增长。</p>
<p>  FireDAC（以前称为AnyDAC）库是唯一一个围绕所有可用的Delphi商业库实现此功能（在FireDAC文档中称为Array DML）的库。启用它可以提高性能，不仅适用于Oracle，还适用于MS SQL，Firebird，DB2，MySQL，Informix和PostgreSQL。</p>
<p>  实际上，在访问Oracle时，我们直接在<code>SynDBOracle</code>中的实现仍然比ZDBC/FireDAC实现提供了更好的性能结果。</p>
<p>  实际上，一些现代数据库引擎（例如Oracle或MS SQL）在使用数组绑定时甚至更快，不仅因为网络延迟减少，而且在这样的操作中，最后才执行完整性检查和索引更新。如果您的表有多个索引和约束，使用此功能比在循环中使用存储过程执行单个语句更快。</p>
<h5 id="toc_15">12.3.4.1.2. 更快的IN子句<a class="vnote-anchor" href="#toc_15" data-anchor-icon="#"></a></h5>
<p>  有时，您希望使用巨大的<code>IN</code>子句编写<code>SELECT</code>语句。如果<code>IN</code>表达式中的项目数量稳定，您可以从准备语句中受益，例如：</p>
<pre><code class="lang-sql hljs"> <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> MyTable <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">ID</span> <span class="hljs-keyword">IN</span> [?,?,?,?,?]
</code></pre>
<p>  但是，如果<code>ID</code>数量不固定，则必须创建不带任何参数的表达式，或使用临时表：</p>
<pre><code class="lang-sql hljs"> <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> MyTable <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">ID</span> <span class="hljs-keyword">IN</span> [<span class="hljs-number">1</span>,<span class="hljs-number">4</span>,<span class="hljs-number">8</span>,<span class="hljs-number">12</span>,<span class="hljs-number">24</span>,<span class="hljs-number">27</span>]
</code></pre>
<p>  作为替代方案，<code>SynDBOracle</code>提供了可以转换为Oracle对象的参数数组的绑定功能，您可以将其用作单个参数。</p>
<p>  当前实现支持<code>TInt64DynArray</code>或<code>TRawUTF8DynArray</code>值，如下：</p>
<pre><code class="lang-pascal hljs"><span class="hljs-keyword">var</span>
  arr: TInt64DynArray = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>];
Query := TSQLDBOracleConnectionProperties.NewThreadSafeStatementPrepared(
  <span class="hljs-string">'select * from table where table.id in'</span>+
    <span class="hljs-string">'(select column_value from table(cast(? as SYS.ODCINUMBERLIST)))'</span>);
Query.BindArray(<span class="hljs-number">1</span>, arr);
Query.ExecutePrepared;
</code></pre>
<p>  还支持RawUTF8数组（如果客户端不支持则回退为Int64数组，如Oracle 10）：</p>
<pre><code class="lang-pascal hljs"><span class="hljs-keyword">var</span>
  arr: TRawUTF8DynArray = [<span class="hljs-string">'123123423452345'</span>, <span class="hljs-string">'3124234454351324'</span>, <span class="hljs-string">'53567568578867867'</span>];
Query := TSQLDBOracleConnectionProperties.NewThreadSafeStatementPrepared(
  <span class="hljs-string">'select * from table where table.id in'</span>+
    <span class="hljs-string">'(select column_value from table(cast(? as SYS.ODCIVARCHAR2LIST)))'</span>);
Query.BindArray(<span class="hljs-number">1</span>, arr);
Query.ExecutePrepared;
</code></pre>
<p>  相较于临时表的解决方案，从生产测试来看，这种实现速度提高了2-100倍（取决于数组和表大小），也更简单。</p>
<p>  缺点是它现在只支持<code>SynDBOracle</code>。</p>
<h4 id="toc_16">12.3.4.2. 使用批量插入优化SQL<a class="vnote-anchor" href="#toc_16" data-anchor-icon="#"></a></h4>
<p>  遗憾的是，数组绑定并非适用于所有数据库或库。</p>
<p>  为了最大限度地提高速度，在批次插入期间，mORMot ORM内核能够根据目标数据库生成一些优化的SQL语句，以便一次发送多行数据。将多个对象保存到外部数据库时，会起到明显的速度提升。</p>
<p>  自动生成多条INSERT语句可用于：</p>
<ul>
<li>我们的内部SQLite3引擎（在<code>mORMotSQLite3.pas</code>单元中）;</li>
<li>几乎所有支持的外部SQL数据库访问（在<code>mORMotDB.pas</code>单元中）：SQlite3（3.7.11及更高版本）、MySQL、PostgreSQL、MS SQL Server（2008及更高版本）、Oracle、Firebird、DB2、Informix和NexusDB ；因为它是在SQL级别实现的，所以它也可用于所有支持的访问库，如ODBC、OleDB、Zeos/ZDBC、UniDAC；</li>
<li>在NoSQL形式的“文档数组”插入中，用于MongoDB数据库（在<code>mORMotMongoDB.pas</code>单元中）。</li>
<li>这意味着即使没有实现数组绑定的驱动程序（如OleDB、ODBC或UniDAC）也能够大大提高数据插入能力。</li>
</ul>
<p>  SQlite3、MySQL、PostgreSQL、MSSQL 2008、DB2、Informix和NexusDB使用SQL-92标准语法使用参数处理具有多个<code>VALUES</code>的<code>INSERT</code>语句：</p>
<pre><code class="lang-sql hljs"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">TABLE</span> (<span class="hljs-keyword">column</span>-a, [<span class="hljs-keyword">column</span>-b, ...])
<span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'value-1a'</span>, [<span class="hljs-string">'value-1b'</span>, ...]),
       (<span class="hljs-string">'value-2a'</span>, [<span class="hljs-string">'value-2b'</span>, ...]),
       ...
</code></pre>
<p>  Oracle实现了奇怪但相似的语法（注意最后的强制<code>SELECT</code>）：</p>
<pre><code class="lang-sql hljs"><span class="hljs-keyword">INSERT</span> ALL
  <span class="hljs-keyword">INTO</span> phone_book <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'John Doe'</span>, <span class="hljs-string">'555-1212'</span>)
  <span class="hljs-keyword">INTO</span> phone_book <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'Peter Doe'</span>, <span class="hljs-string">'555-2323'</span>)
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> DUAL;
</code></pre>
<p>  Firebird实现了自己的语法：</p>
<pre><code class="lang-sql hljs"><span class="hljs-keyword">execute</span> <span class="hljs-keyword">block</span>
<span class="hljs-keyword">as</span>
<span class="hljs-keyword">begin</span>
  <span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> phone_book <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'John Doe'</span>, <span class="hljs-string">'555-1212'</span>);
  <span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> phone_book <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'Peter Doe'</span>, <span class="hljs-string">'555-2323'</span>);
<span class="hljs-keyword">end</span>
</code></pre>
<p>  因此，使用<code>BatchAdd()</code>方法时，大多数引擎都显示出很好的速度提升。有关数据和详细信息，请参阅<a href="">数据访问基准测试</a>。</p>
<p>  如果您想在应用程序或工作单元模式中使用map/reduce算法，加上ORM数据访问，所有这些增强功能都将加速您的数据处理。大量数据的读写从未如此快速和简单，现在是时候用领域服务的高级代码实现替换存储过程了。</p>
<h2 id="toc_17">12.4. CRUD缓存<a class="vnote-anchor" href="#toc_17" data-anchor-icon="#"></a></h2>
<p>  从框架的修订版1.16开始，已在服务端和客户端的CRUD/RESTful针对特定表或记录实现了记录缓存优化。</p>
<p>  请参阅<a href="">ORM缓存</a>以了解框架中可用的其他数据缓存模式，主要是服务端的SQlite3<a href="">JSON全局缓存</a>。所有mORMot的数据缓存都使用JSON作为存储格式，并发现这种格式简单而有效。</p>
<h3 id="toc_18">12.4.1. 何处缓存<a class="vnote-anchor" href="#toc_18" data-anchor-icon="#"></a></h3>
<p>  事实上，对于<code>TSQLRestClient</code>和<code>TSQLRestServer</code>类，<code>TSQLRest</code>都有统一的缓存机制。因此，Delphi客户端可以拥有自己的缓存，而Server也可以拥有自己的缓存。没有任何缓存的客户端（如原始的AJAX客户端）将至少利用服务端缓存。</p>
<p>  默认情况下，REST没有缓存，但您可以使用<code>TSQLRest.Cache</code>属性优化每个<code>TSQLRest</code>实例的缓存策略。</p>
<div class="mermaid-diagram"><svg id="mermaid-diagram-8" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 630.25 797" style="max-width:630.25px;"><style type="text/css" title="mermaid-svg-internal-css">/*  */
#mermaid-diagram-8 .node&gt;rect { ; }
#mermaid-diagram-8 .node text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-8 .edgeLabel text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-8 .cluster rect  { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-8 .cyan&gt;rect, .cyan&gt;polygon, .cyan&gt;circle, .cyan&gt;ellipse { fill:#9ff;  stroke:#fff; }
/*  */
</style><g><g class="output"><g class="clusters"><g class="cluster" id="subGraph3" transform="translate(131.5,639)" style="opacity: 1;"><rect width="223" height="236" x="-111.5" y="-118"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-104" fill="black" stroke="none" id="mermaid-diagram-8Text" style="text-anchor: middle;"> PC Server</text></g><g class="cluster" id="subGraph2" transform="translate(195.5,174.5)" style="opacity: 1;"><rect width="222.5" height="309" x="-111.25" y="-154.5"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-140.5" fill="black" stroke="none" id="mermaid-diagram-8Text" style="text-anchor: middle;"> PC n</text></g><g class="cluster" id="subGraph1" transform="translate(470.25,79)" style="opacity: 1;"><rect width="144" height="118" x="-72" y="-59"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-45" fill="black" stroke="none" id="mermaid-diagram-8Text" style="text-anchor: middle;"> PC 2</text></g><g class="cluster" id="subGraph0" transform="translate(500.25,639)" style="opacity: 1;"><rect width="172.5" height="236" x="-86.25" y="-118"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-104" fill="black" stroke="none" id="mermaid-diagram-8Text" style="text-anchor: middle;"> PC 1</text></g></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M483.02542372881356,614L460.25,639L484,665.0697674418604" marker-end="url(#arrowhead856)" style="fill:none"></path><defs><marker id="arrowhead856" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M529.1271186440678,664L540.25,639L529.1271186440678,614" marker-end="url(#arrowhead857)" style="fill:none"></path><defs><marker id="arrowhead857" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M144.27118644067798,113L130.5,138L130.5,187L145.99698795180723,236" marker-end="url(#arrowhead858)" style="fill:none"></path><defs><marker id="arrowhead858" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M160.84638554216866,236L166.75,187L166.75,138L165.16101694915255,113" marker-end="url(#arrowhead859)" style="fill:none"></path><defs><marker id="arrowhead859" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M144,598.6930693069307L75,639L75,676" marker-end="url(#arrowhead860)" style="fill:none"></path><defs><marker id="arrowhead860" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M160.89830508474577,602L135.5,639L152.66101694915255,664" marker-end="url(#arrowhead861)" style="fill:none"></path><defs><marker id="arrowhead861" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M183.77966101694915,664L189.5,639L181.03389830508473,602" marker-end="url(#arrowhead862)" style="fill:none"></path><defs><marker id="arrowhead862" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M529.1271186440678,546L540.25,521L540.25,472L491.9401408450704,423" marker-end="url(#arrowhead863)" style="fill:none"></path><defs><marker id="arrowhead863" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M470.25,423L470.25,472L470.25,521L488.7881355932203,546" marker-end="url(#arrowhead864)" style="fill:none"></path><defs><marker id="arrowhead864" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M470.25,113L470.25,138L470.25,187L470.25,248" marker-end="url(#arrowhead865)" style="fill:none"></path><defs><marker id="arrowhead865" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M200.5,109L236.75,138L236.75,187L412.25,249.38329764453962" marker-end="url(#arrowhead866)" style="fill:none"></path><defs><marker id="arrowhead866" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M470.25,292L470.25,329L470.25,354L470.25,379" marker-end="url(#arrowhead867)" style="fill:none"></path><defs><marker id="arrowhead867" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M409.75,415.5981308411215L176,472L176,521L176,558" marker-end="url(#arrowhead868)" style="fill:none"></path><defs><marker id="arrowhead868" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M188.4915254237288,602L209.5,639L284.1271186440678,676" marker-end="url(#arrowhead869)" style="fill:none"></path><defs><marker id="arrowhead869" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(540.25,472)" style="opacity: 1;"><g transform="translate(-50,-24)" class="label"><foreignObject width="100" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">JSON + REST<br>over HTTP/1.1</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(470.25,187)" style="opacity: 1;"><g transform="translate(-50,-24)" class="label"><foreignObject width="100" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">JSON + REST<br>over HTTP/1.1</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(236.75,187)" style="opacity: 1;"><g transform="translate(-50,-24)" class="label"><foreignObject width="100" height="48"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">JSON + REST<br>over HTTP/1.1</span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node cyan" id="D1" transform="translate(176,580)" style="opacity: 1;"><rect rx="0" ry="0" x="-32" y="-22" width="64" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-22,-12)"><foreignObject width="44" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Server</div></foreignObject></g></g></g><g class="node cyan" id="D2" transform="translate(75,698)" style="opacity: 1;"><rect rx="0" ry="0" x="-20" y="-22" width="40" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-10,-12)"><foreignObject width="20" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">DB</div></foreignObject></g></g></g><g class="node cyan" id="D3" transform="translate(176,698)" style="opacity: 1;"><rect rx="0" ry="0" x="-31" y="-34" width="62" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-21,-24)"><foreignObject width="42" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">server<br>cache</div></foreignObject></g></g></g><g class="node cyan" id="C1" transform="translate(163,79)" style="opacity: 1;"><rect rx="0" ry="0" x="-37.5" y="-34" width="75" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-27.5,-24)"><foreignObject width="55" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Client n<br>(Delphi)</div></foreignObject></g></g></g><g class="node cyan" id="C2" transform="translate(156.75,270)" style="opacity: 1;"><rect rx="0" ry="0" x="-30" y="-34" width="60" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-20,-24)"><foreignObject width="40" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">client<br>cache</div></foreignObject></g></g></g><g class="node cyan" id="B" transform="translate(470.25,79)" style="opacity: 1;"><rect rx="0" ry="0" x="-37" y="-34" width="74" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-27,-24)"><foreignObject width="54" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Client 2<br>(AJAX)</div></foreignObject></g></g></g><g class="node cyan" id="A1" transform="translate(514,580)" style="opacity: 1;"><rect rx="0" ry="0" x="-37.5" y="-34" width="75" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-27.5,-24)"><foreignObject width="55" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Client 1<br>(Delphi)</div></foreignObject></g></g></g><g class="node cyan" id="A2" transform="translate(514,698)" style="opacity: 1;"><rect rx="0" ry="0" x="-30" y="-34" width="60" height="68"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-20,-24)"><foreignObject width="40" height="48"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">client<br>cache</div></foreignObject></g></g></g><g class="node cyan" id="F" transform="translate(470.25,401)" style="opacity: 1;"><rect rx="0" ry="0" x="-60.5" y="-22" width="121" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-50.5,-12)"><foreignObject width="101" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Local Network</div></foreignObject></g></g></g><g class="node cyan" id="E" transform="translate(470.25,270)" style="opacity: 1;"><rect rx="0" ry="0" x="-58" y="-22" width="116" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-48,-12)"><foreignObject width="96" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Internet(VPN)</div></foreignObject></g></g></g><g class="node cyan" id="G" transform="translate(328.5,698)" style="opacity: 1;"><rect rx="0" ry="0" x="-50.5" y="-22" width="101" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-40.5,-12)"><foreignObject width="81" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">external DB</div></foreignObject></g></g></g></g></g></g></svg></div>
<p>  在服务端为特定记录或表设置缓存后，可以从此缓存中检索内存中的值，而不是每次都调用数据库引擎。正确使用后，这将提高全局服务端响应速度，同样的硬件将支持更多客户端使用。</p>
<p>  在客户端，可以在检索记录时首先检查本地内存缓存。如果找到该项，则客户端将使用此缓存值。如果数据项不在本地缓存中，则查询将像往常一样发送到服务端。由于客户端-服务端远程请求的高延迟，在客户端添加缓存确实有意义。可以调整客户端缓存属性，以便通过Internet正确处理远程HTTP访问，因为这可能比本地网络慢得多。</p>
<p>  我们的缓存实现对CRUD代码是透明的。调用通常的ORM方法来访问记录（<code>Retrieve Update Add</code>），然后客户端或服务端缓存即被使用（如果可用）。对于经常访问相同数据的应用程序，大型应用，记录级缓存可提高性能和可伸缩性。</p>
<h3 id="toc_19">12.4.2. 何时缓存<a class="vnote-anchor" href="#toc_19" data-anchor-icon="#"></a></h3>
<p>  缓存的主要问题是存在多个客户端同时更改和访问数据。</p>
<p>  在当前的实现中，我们的框架使用“悲观”并发控制，依赖于显式锁，以及<a href="">无状态ORM</a>通用设计。由编码人员来确保并发问题不会引起重大混乱。</p>
<p>  您必须在客户端和服务端调整缓存，每一方都可能需要自己的一组缓存选项。</p>
<p>  在您的项目实施中，初期最好不要使用缓存，而是在需要需要提高性能和效率时添加。添加缓存就意味着需要使用自动回归测试，在客户端-服务端多线程架构中，“过早优化是所有邪恶的根源”（Donald Knuth）。</p>
<p>  主要规则可能很简单：</p>
<ul>
<li>如果它可能破坏相关的东西（如全球货币余额值），不要缓存；</li>
<li>除非你需要，否则不要缓存（参见Knuth的智慧）;</li>
<li>确保缓存是值得的（如果某个值可能经常被覆盖，缓存它可能会更慢）;</li>
<li>测试一次，测试两次，总是测试，不要忘记多多测试。</li>
</ul>
<p>  在实践中，缓存问题可能很难跟踪。因此，如果有疑问（为什么这些数据不准确？听起来像是旧版本？），您可以立即禁用缓存，然后确认您的缓存策略问题。</p>
<h3 id="toc_20">12.4.3. 缓存什么<a class="vnote-anchor" href="#toc_20" data-anchor-icon="#"></a></h3>
<p>  两端均需要优化缓存的主要思路是，可以全局配置设置，或者针对不太可能经常变化并由多个客户端同时访问的数据，例如在线零售商的产品线信息。</p>
<p>  缓存的另一个好的用途是存储更改的数据，但一次只能由一个客户端访问。通过在客户端设置此类内容缓存，将不会经常调用服务端检索特定于客户端的数据。在这种情况下，不会出现对缓存数据的并发访问处理问题。</p>
<p>  可能需要进行分析以识别在客户端-服务端的缓存中要登记哪些数据。由于独特的客户端性能分析功能，与mORMot集成的日志功能，可以非常方便地调整缓存设置。</p>
<p>  大多数情况下，人们对业务逻辑的推测足以设置哪些数据将被缓存在各个侧，并确保内容的一致性。</p>
<h3 id="toc_21">12.4.4. 如何缓存<a class="vnote-anchor" href="#toc_21" data-anchor-icon="#"></a></h3>
<p>  可以在ID级别为<code>TSQLRestClient</code>和<code>TSQLRestServer</code>类定义优化的缓存机制。</p>
<p>  默认情况下，禁用REST级别缓存，直到您完成<code>TSQLRest.Cache</code>的<code>SetCache()</code>和<code>SetTimeOut()</code>方法调用。这些方法将定义缓存策略，能够指定在客户端或服务端缓存哪些表或记录。</p>
<p>  一旦在给定表上启用了表和一组ID，对<code>TSQLRest.Retrieve(aClass，aID)</code>或<code>TSQLRecord.Create(aRest，aID)</code>的任何调用将首先尝试从<code>TSQLRestCache</code>实例的内存缓存检索给定aID的<code>TSQLRecord</code>（如果可用）。</p>
<p>  请注意，更复杂的请求（如ID主键以外的其他字段上的查询或JOIN查询）将不会在REST级别进行缓存。但是这样的请求可能会受益于服务端SQLite3级别的JSON全局缓存。</p>
<p>  例如，以下是针对一条记录测试客户端缓存的方法：</p>
<pre><code class="lang-pascal hljs">    (...)
    Client.Cache.SetCache(TSQLRecordPeople); <span class="hljs-comment">// cache whole table</span>
    TestOne;
    Client.Cache.Clear; <span class="hljs-comment">// reset cache settings</span>
    Client.Cache.SetCache(Rec); <span class="hljs-comment">// cache one record</span>
    <span class="hljs-comment">// same as Client.Cache.SetCache(TSQLRecordPeople,Rec.ID);</span>
    TestOne;
    (...)
    Database.Cache.SetCache(TSQLRecordPeople); <span class="hljs-comment">// server-side</span>
    (...)
</code></pre>
<p>  在上面的代码中，<code>Client.Cache.Clear</code>用于重置所有缓存设置（即不仅刷新缓存内容，而且删除以前使用<code>Cache.SetCache()</code>或<code>Cache.SetTimeOut()</code>调用所做的所有设置。所以在上面代码，首先为整个<code>TSQLRecordPeople</code>表启用全局高速缓存，之后重置高速缓存设置，最后仅为特定的记录启用高速缓存。</p>
<p>  要重置缓存内容（如您认为某些值可能已被弃用），只需调用<code>Cache.Flush方法</code>（能够刷新所有表、给定表或给定记录的内存缓存）。</p>
<p>  需要特别指出的是，确保这些缓存在网络上保持一致是由代码负责的。服务端和客户端都有自己的一致性配置文件。缓存策略必须与您的数据模型和应用程序用例相匹配。</p>
<p>  在客户端，仅跟踪本地CRUD操作。根据无状态设计，添加超时值确实有意义，除非已知相应的数据专用于此特定客户端（如会话数据）。如果没有设置超时时间，则由客户端根据需要调用<code>TSQLRestClient.Cache.Flush()</code>方法刷新自己的缓存。</p>
<p>  在服务端，将跟踪ORM的所有CRUD操作（<code>Add / Update / Delete</code>），并在数据变更时通知缓存。但是当前实现不会直接跟踪更改表内容的SQL语句（如带有<code>WHERE</code>子句的一行或多行的<code>UPDATE</code>或<code>DELETE</code>）：在这种情况下，您必须手动刷新服务器缓存内容，以强制保证数据一致性。如果在服务端确实发生了这样的语句，则要调用<code>TSQLRestServer.Cache.Flush()</code>方法，如在执行相应SQL的服务中。如果在客户端确实发生了这样的非CRUD语句，则可以通过专用的<code>TSQLRestClientURI.ServerCacheFlush()</code>方法确保服务器内容与客户端一致，该方法将调用服务器上的专用标准服务，用于刷新其缓存内容。</p>

    </div>
</div>
</div>

<div id="container-floating" style="display:none;" class="d-none d-md-block d-xl-block">
    <div id="floating-button" onclick="toggleMore()">
        <p id="floating-more" class="more">&gt;</p>
    </div>
</div>

<!--
<div class="footer" id="vnote-footer">
    <p>Generated by <em><a href="https://tamlok.github.io/vnote/">VNote</a></em>.</p>
</div>
-->
</body>
</html>
